am 5ff04590: am 4ea5bd05: Merge "Revert "netd: reduce privileges""

* commit '5ff04590386a08712d83c4f8add6d78870fe3bce':
  Revert "netd: reduce privileges"
diff --git a/CommandListener.cpp b/CommandListener.cpp
index e8876b5..026797f 100644
--- a/CommandListener.cpp
+++ b/CommandListener.cpp
@@ -92,6 +92,11 @@
         NULL,
 };
 
+static const char* MANGLE_OUTPUT[] = {
+        SecondaryTableController::LOCAL_MANGLE_OUTPUT,
+        NULL,
+};
+
 static const char* NAT_PREROUTING[] = {
         OEM_IPTABLES_NAT_PREROUTING,
         NULL,
@@ -99,6 +104,7 @@
 
 static const char* NAT_POSTROUTING[] = {
         NatController::LOCAL_NAT_POSTROUTING,
+        SecondaryTableController::LOCAL_NAT_POSTROUTING,
         NULL,
 };
 
@@ -176,6 +182,7 @@
     createChildChains(V4V6, "filter", "OUTPUT", FILTER_OUTPUT);
     createChildChains(V4V6, "raw", "PREROUTING", RAW_PREROUTING);
     createChildChains(V4V6, "mangle", "POSTROUTING", MANGLE_POSTROUTING);
+    createChildChains(V4V6, "mangle", "OUTPUT", MANGLE_OUTPUT);
     createChildChains(V4, "nat", "PREROUTING", NAT_PREROUTING);
     createChildChains(V4, "nat", "POSTROUTING", NAT_POSTROUTING);
 
@@ -254,10 +261,64 @@
             return 0;
         }
 
-        //     0       1       2        3          4           5     6      7
-        // interface route add/remove iface default/secondary dest prefix gateway
+        //     0       1       2        3          4           5        6      7
+        // interface route add/remove iface default/secondary dest    prefix gateway
+        // interface route  fwmark  add/remove   iface
+        // interface route    uid   add/remove   iface      uid_start  uid_end
         if (!strcmp(argv[1], "route")) {
             int prefix_length = 0;
+            if (!strcmp(argv[2], "fwmark")) {
+                if (argc < 5) {
+                    cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
+                    return 0;
+                }
+                if (!strcmp(argv[3], "add")) {
+                    if (!sSecondaryTableCtrl->addFwmarkRule(argv[4])) {
+                        cli->sendMsg(ResponseCode::CommandOkay, "Fwmark rule successfully added",
+                                false);
+                    } else {
+                        cli->sendMsg(ResponseCode::OperationFailed, "Failed to add fwmark rule",
+                                true);
+                    }
+                } else if (!strcmp(argv[3], "remove")) {
+                    if (!sSecondaryTableCtrl->removeFwmarkRule(argv[4])) {
+                        cli->sendMsg(ResponseCode::CommandOkay, "Fwmark rule successfully removed",
+                                false);
+                    } else {
+                        cli->sendMsg(ResponseCode::OperationFailed, "Failed to remove fwmark rule",
+                                true);
+                    }
+                } else {
+                    cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown fwmark cmd", false);
+                }
+                return 0;
+            }
+            if (!strcmp(argv[2], "uid")) {
+                if (argc < 7) {
+                    cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
+                    return 0;
+                }
+                if (!strcmp(argv[3], "add")) {
+                    if (!sSecondaryTableCtrl->addUidRule(argv[4], atoi(argv[5]), atoi(argv[6]))) {
+                        cli->sendMsg(ResponseCode::CommandOkay, "uid rule successfully added",
+                                false);
+                    } else {
+                        cli->sendMsg(ResponseCode::OperationFailed, "Failed to add uid rule", true);
+                    }
+                } else if (!strcmp(argv[3], "remove")) {
+                    if (!sSecondaryTableCtrl->removeUidRule(argv[4],
+                                atoi(argv[5]), atoi(argv[6]))) {
+                        cli->sendMsg(ResponseCode::CommandOkay, "uid rule successfully removed",
+                                false);
+                    } else {
+                        cli->sendMsg(ResponseCode::OperationFailed, "Failed to remove uid rule",
+                                true);
+                    }
+                } else {
+                    cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown uid cmd", false);
+                }
+                return 0;
+            }
             if (argc < 8) {
                 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
                 return 0;
@@ -462,6 +523,31 @@
                         "Failed to change IPv6 state", true);
             }
             return 0;
+        } else if (!strcmp(argv[1], "getmtu")) {
+            char *msg = NULL;
+            int mtu = 0;
+            if (sInterfaceCtrl->getMtu(argv[2], &mtu) == 0) {
+                asprintf(&msg, "MTU = %d", mtu);
+                cli->sendMsg(ResponseCode::InterfaceGetMtuResult, msg, false);
+                free(msg);
+            } else {
+                cli->sendMsg(ResponseCode::OperationFailed,
+                        "Failed to get MTU", true);
+            }
+            return 0;
+        } else if (!strcmp(argv[1], "setmtu")) {
+            if (argc != 4) {
+                cli->sendMsg(ResponseCode::CommandSyntaxError,
+                        "Usage: interface setmtu <interface> <val>", false);
+                return 0;
+            }
+            if (sInterfaceCtrl->setMtu(argv[2], argv[3]) == 0) {
+                cli->sendMsg(ResponseCode::CommandOkay, "MTU changed", false);
+            } else {
+                cli->sendMsg(ResponseCode::OperationFailed,
+                        "Failed to get MTU", true);
+            }
+            return 0;
         } else {
             cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown interface cmd", false);
             return 0;
@@ -767,9 +853,10 @@
         NetdCommand("resolver") {
 }
 
-int CommandListener::ResolverCmd::runCommand(SocketClient *cli, int argc, char **argv) {
+int CommandListener::ResolverCmd::runCommand(SocketClient *cli, int argc, char **margv) {
     int rc = 0;
     struct in_addr addr;
+    const char **argv = const_cast<const char **>(margv);
 
     if (argc < 2) {
         cli->sendMsg(ResponseCode::CommandSyntaxError, "Resolver missing arguments", false);
@@ -835,6 +922,29 @@
                     "Wrong number of arguments to resolver clearifaceforpid", false);
             return 0;
         }
+    } else if (!strcmp(argv[1], "setifaceforuidrange")) { // resolver setifaceforuid <iface> <l> <h>
+        if (argc == 5) {
+            rc = sResolverCtrl->setDnsInterfaceForUidRange(argv[2], atoi(argv[3]), atoi(argv[4]));
+        } else {
+            cli->sendMsg(ResponseCode::CommandSyntaxError,
+                    "Wrong number of arguments to resolver setifaceforuid", false);
+            return 0;
+        }
+    } else if (!strcmp(argv[1], "clearifaceforuidrange")) { // resolver clearifaceforuid <l> <h>
+        if (argc == 4) {
+            rc = sResolverCtrl->clearDnsInterfaceForUidRange(atoi(argv[2]), atoi(argv[3]));
+        } else {
+            cli->sendMsg(ResponseCode::CommandSyntaxError,
+                    "Wrong number of arguments to resolver clearifaceforuid", false);
+            return 0;
+        }
+    } else if (!strcmp(argv[1], "clearifacemapping")) {
+        if (argc == 2) {
+            rc = sResolverCtrl->clearDnsInterfaceMappings();
+        } else {
+            cli->sendMsg(ResponseCode::CommandSyntaxError,
+                    "Wrong number of arugments to resolver clearifacemapping", false);
+        }
     } else {
         cli->sendMsg(ResponseCode::CommandSyntaxError,"Resolver unknown command", false);
         return 0;
diff --git a/DnsProxyListener.cpp b/DnsProxyListener.cpp
index cee8d10..18fa267 100644
--- a/DnsProxyListener.cpp
+++ b/DnsProxyListener.cpp
@@ -50,13 +50,15 @@
                                                          char* service,
                                                          struct addrinfo* hints,
                                                          char* iface,
-                                                         pid_t pid)
+                                                         pid_t pid,
+                                                         uid_t uid)
         : mClient(c),
           mHost(host),
           mService(service),
           mHints(hints),
           mIface(iface),
-          mPid(pid) {
+          mPid(pid),
+          mUid(uid) {
 }
 
 DnsProxyListener::GetAddrInfoHandler::~GetAddrInfoHandler() {
@@ -124,7 +126,9 @@
 
     char tmp[IF_NAMESIZE + 1];
     if (mIface == NULL) {
-        _resolv_get_pids_associated_interface(mPid, tmp, sizeof(tmp));
+        //fall back to the per uid interface if no per pid interface exists
+        if(!_resolv_get_pids_associated_interface(mPid, tmp, sizeof(tmp)))
+            _resolv_get_uids_associated_interface(mUid, tmp, sizeof(tmp));
     }
 
     struct addrinfo* result = NULL;
@@ -202,6 +206,7 @@
     int ai_socktype = atoi(argv[5]);
     int ai_protocol = atoi(argv[6]);
     pid_t pid = cli->getPid();
+    uid_t uid = cli->getUid();
 
     if (ai_flags != -1 || ai_family != -1 ||
         ai_socktype != -1 || ai_protocol != -1) {
@@ -213,16 +218,16 @@
     }
 
     if (DBG) {
-        ALOGD("GetAddrInfoHandler for %s / %s / %s / %d",
+        ALOGD("GetAddrInfoHandler for %s / %s / %s / %d / %d",
              name ? name : "[nullhost]",
              service ? service : "[nullservice]",
              iface ? iface : "[nulliface]",
-             pid);
+             pid, uid);
     }
 
     cli->incRef();
     DnsProxyListener::GetAddrInfoHandler* handler =
-        new DnsProxyListener::GetAddrInfoHandler(cli, name, service, hints, iface, pid);
+        new DnsProxyListener::GetAddrInfoHandler(cli, name, service, hints, iface, pid, uid);
     handler->start();
 
     return 0;
@@ -252,6 +257,7 @@
     }
 
     pid_t pid = cli->getPid();
+    uid_t uid = cli->getUid();
     char* iface = argv[1];
     char* name = argv[2];
     int af = atoi(argv[3]);
@@ -270,7 +276,7 @@
 
     cli->incRef();
     DnsProxyListener::GetHostByNameHandler* handler =
-            new DnsProxyListener::GetHostByNameHandler(cli, pid, iface, name, af);
+            new DnsProxyListener::GetHostByNameHandler(cli, pid, uid, iface, name, af);
     handler->start();
 
     return 0;
@@ -278,11 +284,13 @@
 
 DnsProxyListener::GetHostByNameHandler::GetHostByNameHandler(SocketClient* c,
                                                              pid_t pid,
+                                                             uid_t uid,
                                                              char* iface,
                                                              char* name,
                                                              int af)
         : mClient(c),
           mPid(pid),
+          mUid(uid),
           mIface(iface),
           mName(name),
           mAf(af) {
@@ -315,7 +323,9 @@
 
     char iface[IF_NAMESIZE + 1];
     if (mIface == NULL) {
-        _resolv_get_pids_associated_interface(mPid, iface, sizeof(iface));
+        //fall back to the per uid interface if no per pid interface exists
+        if(!_resolv_get_pids_associated_interface(mPid, iface, sizeof(iface)))
+            _resolv_get_uids_associated_interface(mUid, iface, sizeof(iface));
     }
 
     struct hostent* hp;
@@ -371,6 +381,7 @@
     int addrLen = atoi(argv[2]);
     int addrFamily = atoi(argv[3]);
     pid_t pid = cli->getPid();
+    uid_t uid = cli->getUid();
     char* iface = argv[4];
 
     if (strcmp(iface, "^") == 0) {
@@ -394,7 +405,7 @@
 
     cli->incRef();
     DnsProxyListener::GetHostByAddrHandler* handler =
-            new DnsProxyListener::GetHostByAddrHandler(cli, addr, addrLen, addrFamily, iface ,pid);
+            new DnsProxyListener::GetHostByAddrHandler(cli, addr, addrLen, addrFamily, iface, pid, uid);
     handler->start();
 
     return 0;
@@ -405,13 +416,15 @@
                                                              int   addressLen,
                                                              int   addressFamily,
                                                              char* iface,
-                                                             pid_t pid)
+                                                             pid_t pid,
+                                                             uid_t uid)
         : mClient(c),
           mAddress(address),
           mAddressLen(addressLen),
           mAddressFamily(addressFamily),
           mIface(iface),
-          mPid(pid) {
+          mPid(pid),
+          mUid(uid) {
 }
 
 DnsProxyListener::GetHostByAddrHandler::~GetHostByAddrHandler() {
@@ -441,9 +454,10 @@
 
     char tmp[IF_NAMESIZE + 1];
     if (mIface == NULL) {
-        _resolv_get_pids_associated_interface(mPid, tmp, sizeof(tmp));
+        //fall back to the per uid interface if no per pid interface exists
+        if(!_resolv_get_pids_associated_interface(mPid, tmp, sizeof(tmp)))
+            _resolv_get_uids_associated_interface(mUid, tmp, sizeof(tmp));
     }
-
     struct hostent* hp;
 
     // NOTE gethostbyaddr should take a void* but bionic thinks it should be char*
diff --git a/DnsProxyListener.h b/DnsProxyListener.h
index c950c02..758ca76 100644
--- a/DnsProxyListener.h
+++ b/DnsProxyListener.h
@@ -42,7 +42,8 @@
                            char* service,
                            struct addrinfo* hints,
                            char* iface,
-                           pid_t pid);
+                           pid_t pid,
+                           uid_t uid);
         ~GetAddrInfoHandler();
 
         static void* threadStart(void* handler);
@@ -56,6 +57,7 @@
         struct addrinfo* mHints;  // owned
         char* mIface; // owned
         pid_t mPid;
+        uid_t mUid;
     };
 
     /* ------ gethostbyname ------*/
@@ -70,6 +72,7 @@
     public:
         GetHostByNameHandler(SocketClient *c,
                             pid_t pid,
+                            uid_t uid,
                             char *iface,
                             char *name,
                             int af);
@@ -80,6 +83,7 @@
         void run();
         SocketClient* mClient; //ref counted
         pid_t mPid;
+        uid_t mUid;
         char* mIface; // owned
         char* mName; // owned
         int mAf;
@@ -100,7 +104,8 @@
                             int   addressLen,
                             int   addressFamily,
                             char* iface,
-                            pid_t pid);
+                            pid_t pid,
+                            uid_t uid);
         ~GetHostByAddrHandler();
 
         static void* threadStart(void* handler);
@@ -114,6 +119,7 @@
         int   mAddressFamily;  // address family
         char* mIface; // owned
         pid_t mPid;
+        uid_t mUid;
     };
 };
 
diff --git a/InterfaceController.cpp b/InterfaceController.cpp
index 0d8f121..c305be9 100644
--- a/InterfaceController.cpp
+++ b/InterfaceController.cpp
@@ -46,6 +46,8 @@
 
 const char ipv6_proc_path[] = "/proc/sys/net/ipv6/conf";
 
+const char sys_net_path[] = "/sys/class/net";
+
 InterfaceController::InterfaceController()
 	: sendCommand_(NULL) {
 	// Initial IPv6 settings.
@@ -163,3 +165,26 @@
 	closedir(dir);
 	return 0;
 }
+
+int InterfaceController::getMtu(const char *interface, int *mtu)
+{
+	char buf[16];
+	int size = sizeof(buf);
+	char *path;
+	asprintf(&path, "%s/%s/mtu", sys_net_path, interface);
+	int success = readFile(path, buf, &size);
+	if (!success && mtu)
+		*mtu = atoi(buf);
+	free(path);
+	return success;
+
+}
+
+int InterfaceController::setMtu(const char *interface, const char *mtu)
+{
+	char *path;
+	asprintf(&path, "%s/%s/mtu", sys_net_path, interface);
+	int success = writeFile(path, mtu, strlen(mtu));
+	free(path);
+	return success;
+}
diff --git a/InterfaceController.h b/InterfaceController.h
index 5943a9a..b8bbc92 100644
--- a/InterfaceController.h
+++ b/InterfaceController.h
@@ -35,6 +35,8 @@
 	int interfaceCommand(int argc, char *argv[], char **rbuf);
 	int setEnableIPv6(const char *interface, const int on);
 	int setIPv6PrivacyExtensions(const char *interface, const int on);
+	int getMtu(const char *interface, int *mtu);
+	int setMtu(const char *interface, const char *mtu);
 
  private:
 	void *libh_;
diff --git a/NetdConstants.cpp b/NetdConstants.cpp
index 1ab09a5..c3c16eb 100644
--- a/NetdConstants.cpp
+++ b/NetdConstants.cpp
@@ -122,3 +122,24 @@
     close(fd);
     return 0;
 }
+
+int readFile(const char *path, char *buf, int *sizep)
+{
+    int fd = open(path, O_RDONLY);
+    int size;
+
+    if (fd < 0) {
+        ALOGE("Failed to open %s: %s", path, strerror(errno));
+        return -1;
+    }
+
+    size = read(fd, buf, *sizep);
+    if (size < 0) {
+        ALOGE("Failed to write %s: %s", path, strerror(errno));
+        close(fd);
+        return -1;
+    }
+    *sizep = size;
+    close(fd);
+    return 0;
+}
diff --git a/NetdConstants.h b/NetdConstants.h
index eb59af2..d686968 100644
--- a/NetdConstants.h
+++ b/NetdConstants.h
@@ -34,6 +34,7 @@
 int execIptables(IptablesTarget target, ...);
 int execIptablesSilently(IptablesTarget target, ...);
 int writeFile(const char *path, const char *value, int size);
+int readFile(const char *path, char *buf, int *sizep);
 
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
 
diff --git a/ResolverController.cpp b/ResolverController.cpp
index 13dd930..e61fae7 100644
--- a/ResolverController.cpp
+++ b/ResolverController.cpp
@@ -38,7 +38,7 @@
 }
 
 int ResolverController::setInterfaceDnsServers(const char* iface, const char* domains,
-        char** servers, int numservers) {
+        const char** servers, int numservers) {
     if (DBG) {
         ALOGD("setInterfaceDnsServers iface = %s\n", iface);
     }
@@ -96,3 +96,30 @@
 
     return 0;
 }
+
+int ResolverController::setDnsInterfaceForUidRange(const char* iface, int uid_start, int uid_end) {
+    if (DBG) {
+        ALOGD("setDnsIfaceForUidRange iface = %s, range = [%d,%d]\n", iface, uid_start, uid_end);
+    }
+
+    return _resolv_set_iface_for_uid_range(iface, uid_start, uid_end);
+}
+
+int ResolverController::clearDnsInterfaceForUidRange(int uid_start, int uid_end) {
+    if (DBG) {
+        ALOGD("clearDnsIfaceForUidRange range = [%d,%d]\n", uid_start, uid_end);
+    }
+
+    return _resolv_clear_iface_for_uid_range(uid_start, uid_end);
+}
+
+int ResolverController::clearDnsInterfaceMappings()
+{
+    if (DBG) {
+        ALOGD("clearInterfaceMappings\n");
+    }
+    _resolv_clear_iface_uid_range_mapping();
+    _resolv_clear_iface_pid_mapping();
+
+    return 0;
+}
diff --git a/ResolverController.h b/ResolverController.h
index a21e077..e705c8f 100644
--- a/ResolverController.h
+++ b/ResolverController.h
@@ -26,13 +26,16 @@
     virtual ~ResolverController() {};
 
     int setDefaultInterface(const char* iface);
-    int setInterfaceDnsServers(const char* iface, const char * domains, char** servers,
+    int setInterfaceDnsServers(const char* iface, const char * domains, const 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);
+    int setDnsInterfaceForUidRange(const char* iface, int uid_start, int uid_end);
+    int clearDnsInterfaceForUidRange(int uid_start, int uid_end);
+    int clearDnsInterfaceMappings();
 };
 
 #endif /* _RESOLVER_CONTROLLER_H_ */
diff --git a/ResponseCode.h b/ResponseCode.h
index 7689ef8..85f183a 100644
--- a/ResponseCode.h
+++ b/ResponseCode.h
@@ -45,6 +45,7 @@
     static const int TetheringStatsResult      = 221;
     static const int DnsProxyQueryResult       = 222;
     static const int ClatdStatusResult         = 223;
+    static const int InterfaceGetMtuResult     = 224;
 
     // 400 series - The command was accepted but the requested action
     // did not take place.
diff --git a/SecondaryTableController.cpp b/SecondaryTableController.cpp
index ce23d28..222a0e0 100644
--- a/SecondaryTableController.cpp
+++ b/SecondaryTableController.cpp
@@ -36,6 +36,9 @@
 #include "NetdConstants.h"
 #include "SecondaryTableController.h"
 
+const char* SecondaryTableController::LOCAL_MANGLE_OUTPUT = "st_mangle_OUTPUT";
+const char* SecondaryTableController::LOCAL_NAT_POSTROUTING = "st_nat_POSTROUTING";
+
 SecondaryTableController::SecondaryTableController() {
     int i;
     for (i=0; i < INTERFACES_TRACKED; i++) {
@@ -232,6 +235,93 @@
 
     return runCmd(ARRAY_SIZE(cmd), cmd);
 }
+int SecondaryTableController::addFwmarkRule(const char *iface) {
+    return setFwmarkRule(iface, true);
+}
+
+int SecondaryTableController::removeFwmarkRule(const char *iface) {
+    return setFwmarkRule(iface, false);
+}
+
+int SecondaryTableController::setFwmarkRule(const char *iface, bool add) {
+    char tableIndex_str[11];
+    int tableIndex = findTableNumber(iface);
+    if (tableIndex == -1) {
+        tableIndex = findTableNumber(""); // look for an empty slot
+        if (tableIndex == -1) {
+            ALOGE("Max number of NATed interfaces reached");
+            errno = ENODEV;
+            return -1;
+        }
+        strncpy(mInterfaceTable[tableIndex], iface, IFNAMSIZ);
+        // Ensure null termination even if truncation happened
+        mInterfaceTable[tableIndex][IFNAMSIZ] = 0;
+    }
+    snprintf(tableIndex_str, sizeof(tableIndex_str), "%d", tableIndex +
+            BASE_TABLE_NUMBER);
+    const char *cmd[] = {
+        IP_PATH,
+        "rule",
+        add ? "add" : "del",
+        "fwmark",
+        tableIndex_str,
+        "table",
+        tableIndex_str
+    };
+    int ret = runCmd(ARRAY_SIZE(cmd), cmd);
+    if (ret) return ret;
+
+    //set up the needed source IP rewriting
+    //NOTE: Without ipv6 NAT in the kernel <3.7 only support V4 NAT
+    return execIptables(V4,
+            "-t",
+            "nat",
+            add ? "-A" : "-D",
+            LOCAL_NAT_POSTROUTING,
+            "-o",
+            iface,
+            "-m",
+            "mark",
+            "--mark",
+            tableIndex_str,
+            "-j",
+            "MASQUERADE",
+            NULL);
+
+}
+
+int SecondaryTableController::addUidRule(const char *iface, int uid_start, int uid_end) {
+    return setUidRule(iface, uid_start, uid_end, true);
+}
+
+int SecondaryTableController::removeUidRule(const char *iface, int uid_start, int uid_end) {
+    return setUidRule(iface, uid_start, uid_end, false);
+}
+
+int SecondaryTableController::setUidRule(const char *iface, int uid_start, int uid_end, bool add) {
+    int tableIndex = findTableNumber(iface);
+    if (tableIndex == -1) {
+        return -1;
+    }
+    char tableIndex_str[11] = {0};
+    snprintf(tableIndex_str, sizeof(tableIndex_str), "%d", tableIndex + BASE_TABLE_NUMBER);
+    char uid_str[24] = {0};
+    snprintf(uid_str, sizeof(uid_str), "%d-%d", uid_start, uid_end);
+    return execIptables(V4V6,
+            "-t",
+            "mangle",
+            add ? "-A" : "-D",
+            LOCAL_MANGLE_OUTPUT,
+            "-m",
+            "owner",
+            "--uid-owner",
+            uid_str,
+            "-j",
+            "MARK",
+            "--set-mark",
+            tableIndex_str,
+            NULL);
+}
 
 int SecondaryTableController::runCmd(int argc, const char **argv) {
     int ret = 0;
diff --git a/SecondaryTableController.h b/SecondaryTableController.h
index 8531900..3941ba1 100644
--- a/SecondaryTableController.h
+++ b/SecondaryTableController.h
@@ -40,8 +40,18 @@
     int findTableNumber(const char *iface);
     int modifyFromRule(int tableIndex, const char *action, const char *addr);
     int modifyLocalRoute(int tableIndex, const char *action, const char *iface, const char *addr);
+    int addUidRule(const char *iface, int uid_start, int uid_end);
+    int removeUidRule(const char *iface, int uid_start, int uid_end);
+    int addFwmarkRule(const char *iface);
+    int removeFwmarkRule(const char *iface);
+
+    static const char* LOCAL_MANGLE_OUTPUT;
+    static const char* LOCAL_NAT_POSTROUTING;
+
 
 private:
+    int setUidRule(const char* iface, int uid_start, int uid_end, bool add);
+    int setFwmarkRule(const char *iface, bool add);
     int modifyRoute(SocketClient *cli, const char *action, char *iface, char *dest, int prefix,
             char *gateway, int tableIndex);
 
diff --git a/SoftapController.cpp b/SoftapController.cpp
index 0b1899c..825a376 100644
--- a/SoftapController.cpp
+++ b/SoftapController.cpp
@@ -106,36 +106,53 @@
  * Arguments:
  *  argv[2] - wlan interface
  *  argv[3] - SSID
- *  argv[4] - Security
- *  argv[5] - Key
+ *  argv[4] - Broadcast/Hidden
+ *  argv[5] - Channel
+ *  argv[6] - Security
+ *  argv[7] - Key
  */
 int SoftapController::setSoftap(int argc, char *argv[]) {
     char psk_str[2*SHA256_DIGEST_LENGTH+1];
     int ret = ResponseCode::SoftapStatusResult;
     int i = 0;
     int fd;
-
-    if (argc < 4) {
-        ALOGE("Softap set is missing arguments. Please use: softap <wlan iface> <SSID> <wpa2?-psk|open> <passphrase>");
-        return ResponseCode::CommandSyntaxError;
-    }
-
+    int hidden = 0;
+    int channel = AP_CHANNEL_DEFAULT;
     char *wbuf = NULL;
     char *fbuf = NULL;
 
-    asprintf(&wbuf, "interface=%s\ndriver=nl80211\nctrl_interface="
-            "/data/misc/wifi/hostapd\nssid=%s\nchannel=6\nieee80211n=1\n"
-            "hw_mode=g\n",
-            argv[2], argv[3]);
+    if (argc < 5) {
+        ALOGE("Softap set is missing arguments. Please use:");
+        ALOGE("softap <wlan iface> <SSID> <hidden/broadcast> <channel> <wpa2?-psk|open> <passphrase>");
+        return ResponseCode::CommandSyntaxError;
+    }
 
-    if (argc > 4) {
-        if (!strcmp(argv[4], "wpa-psk")) {
-            generatePsk(argv[3], argv[5], psk_str);
+    if (!strcasecmp(argv[4], "hidden"))
+        hidden = 1;
+
+    if (argc >= 5) {
+        channel = atoi(argv[5]);
+        if (channel <= 0)
+            channel = AP_CHANNEL_DEFAULT;
+    }
+
+    asprintf(&wbuf, "interface=%s\ndriver=nl80211\nctrl_interface="
+            "/data/misc/wifi/hostapd\nssid=%s\nchannel=%d\nieee80211n=1\n"
+            "hw_mode=g\nignore_broadcast_ssid=%d\n",
+            argv[2], argv[3], channel, hidden);
+
+    if (argc > 7) {
+        if (!strcmp(argv[6], "wpa-psk")) {
+            generatePsk(argv[3], argv[7], 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(argv[3], argv[5], psk_str);
+        } else if (!strcmp(argv[6], "wpa2-psk")) {
+            generatePsk(argv[3], argv[7], psk_str);
             asprintf(&fbuf, "%swpa=2\nrsn_pairwise=CCMP\nwpa_psk=%s\n", wbuf, psk_str);
-        } else if (!strcmp(argv[4], "open")) {
+        } else if (!strcmp(argv[6], "open")) {
+            asprintf(&fbuf, "%s", wbuf);
+        }
+    } else if (argc > 6) {
+        if (!strcmp(argv[6], "open")) {
             asprintf(&fbuf, "%s", wbuf);
         }
     } else {
diff --git a/SoftapController.h b/SoftapController.h
index 38ff8ff..7063067 100644
--- a/SoftapController.h
+++ b/SoftapController.h
@@ -25,6 +25,7 @@
 #define AP_BSS_STOP_DELAY	500000
 #define AP_SET_CFG_DELAY	500000
 #define AP_DRIVER_START_DELAY	800000
+#define AP_CHANNEL_DEFAULT	6
 
 class SoftapController {
 public:
diff --git a/ndc.c b/ndc.c
index 29a399a..1f76c2a 100644
--- a/ndc.c
+++ b/ndc.c
@@ -65,14 +65,23 @@
 }
 
 static int do_cmd(int sock, int argc, char **argv) {
-    char *final_cmd = strdup("0 ");
-    if (final_cmd == NULL) {
-        perror("strdup");
-        return errno;
-    }
-
+    char *final_cmd;
+    char *conv_ptr;
     int i;
 
+    /* Check if 1st arg is cmd sequence number */ 
+    strtol(argv[1], &conv_ptr, 10);
+    if (conv_ptr == argv[1]) {
+        final_cmd = strdup("0 ");
+    } else {
+        final_cmd = strdup("");
+    }
+    if (final_cmd == NULL) {
+        int res = errno;
+        perror("strdup failed");
+        return res;
+    }
+
     for (i = 1; i < argc; i++) {
         if (index(argv[i], '"')) {
             perror("argument with embedded quotes not allowed");
@@ -81,22 +90,24 @@
         }
         bool needs_quoting = index(argv[i], ' ');
         const char *format = needs_quoting ? "%s\"%s\"%s" : "%s%s%s";
-        char *cmp;
+        char *tmp_final_cmd;
 
-        if (asprintf(&cmp, format, final_cmd, argv[i],
-                     (i == (argc -1)) ? "" : " ") < 0) {
-            perror("malloc");
+        if (asprintf(&tmp_final_cmd, format, final_cmd, argv[i],
+                     (i == (argc - 1)) ? "" : " ") < 0) {
+            int res = errno;
+            perror("failed asprintf");
             free(final_cmd);
-            return errno;
+            return res;
         }
         free(final_cmd);
-        final_cmd = cmp;
+        final_cmd = tmp_final_cmd;
     }
 
     if (write(sock, final_cmd, strlen(final_cmd) + 1) < 0) {
+        int res = errno;
         perror("write");
         free(final_cmd);
-        return errno;
+        return res;
     }
     free(final_cmd);
 
@@ -121,9 +132,10 @@
         FD_SET(sock, &read_fds);
 
         if ((rc = select(sock +1, &read_fds, NULL, NULL, &to)) < 0) {
+            int res = errno;
             fprintf(stderr, "Error in select (%s)\n", strerror(errno));
             free(buffer);
-            return errno;
+            return res;
         } else if (!rc) {
             continue;
             fprintf(stderr, "[TIMEOUT]\n");
@@ -131,6 +143,7 @@
         } else if (FD_ISSET(sock, &read_fds)) {
             memset(buffer, 0, 4096);
             if ((rc = read(sock, buffer, 4096)) <= 0) {
+                int res = errno;
                 if (rc == 0)
                     fprintf(stderr, "Lost connection to Netd - did it crash?\n");
                 else
@@ -138,7 +151,7 @@
                 free(buffer);
                 if (rc == 0)
                     return ECONNRESET;
-                return errno;
+                return res;
             }
 
             int offset = 0;
@@ -168,6 +181,6 @@
 }
 
 static void usage(char *progname) {
-    fprintf(stderr, "Usage: %s [sockname] <monitor>|<cmd> [arg1] [arg2...]\n", progname);
+    fprintf(stderr, "Usage: %s [<sockname>] ([monitor] | ([<cmd_seq_num>] <cmd> [arg ...]))\n", progname);
     exit(1);
 }