Keep better tabs on secondary tables.

We had some places (NatController) where routes were being set
but not accounted for in the number-of-routes talley so we
could end up thinking the table was empty and not clean up
after ourselves properly.

Also consolidated constants.

bug:5917475
Change-Id: I98a41d433e1d4b4ca6692fb2328e2c9afc828145
diff --git a/SecondaryTableController.cpp b/SecondaryTableController.cpp
index 5d79f86..5939924 100644
--- a/SecondaryTableController.cpp
+++ b/SecondaryTableController.cpp
@@ -34,12 +34,9 @@
 extern "C" int system_nosh(const char *command);
 
 #include "ResponseCode.h"
+#include "NetdConstants.h"
 #include "SecondaryTableController.h"
 
-static char IP_PATH[] = "/system/bin/ip";
-static char ADD[] = "add";
-static char DEL[] = "del";
-
 SecondaryTableController::SecondaryTableController() {
     int i;
     for (i=0; i < INTERFACES_TRACKED; i++) {
@@ -79,8 +76,8 @@
     return modifyRoute(cli, ADD, iface, dest, prefix, gateway, tableIndex);
 }
 
-int SecondaryTableController::modifyRoute(SocketClient *cli, char *action, char *iface, char *dest,
-        int prefix, char *gateway, int tableIndex) {
+int SecondaryTableController::modifyRoute(SocketClient *cli, const char *action, char *iface,
+        char *dest, int prefix, char *gateway, int tableIndex) {
     char *cmd;
 
     if (strcmp("::", gateway) == 0) {
@@ -108,10 +105,40 @@
             mInterfaceTable[tableIndex][0] = 0;
         }
     }
+    modifyRuleCount(tableIndex, action);
     cli->sendMsg(ResponseCode::CommandOkay, "Route modified", false);
     return 0;
 }
 
+void SecondaryTableController::modifyRuleCount(int tableIndex, const char *action) {
+    if (strcmp(action, ADD) == 0) {
+        mInterfaceRuleCount[tableIndex]++;
+    } else {
+        if (--mInterfaceRuleCount[tableIndex] < 1) {
+            mInterfaceRuleCount[tableIndex] = 0;
+            mInterfaceTable[tableIndex][0] = 0;
+        }
+    }
+}
+
+int SecondaryTableController::verifyTableIndex(int tableIndex) {
+    if ((tableIndex < 0) ||
+            (tableIndex >= INTERFACES_TRACKED) ||
+            (mInterfaceTable[tableIndex][0] == 0)) {
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
+const char *SecondaryTableController::getVersion(const char *addr) {
+    if (strchr(addr, ':') != NULL) {
+        return "-6";
+    } else {
+        return "-4";
+    }
+}
+
 int SecondaryTableController::removeRoute(SocketClient *cli, char *iface, char *dest, int prefix,
         char *gateway) {
     int tableIndex = findTableNumber(iface);
@@ -125,12 +152,46 @@
     return modifyRoute(cli, DEL, iface, dest, prefix, gateway, tableIndex);
 }
 
+int SecondaryTableController::modifyFromRule(int tableIndex, const char *action,
+        const char *addr) {
+    char *cmd;
+
+    if (verifyTableIndex(tableIndex)) {
+        return -1;
+    }
+    asprintf(&cmd, "%s %s rule %s from %s table %d", IP_PATH, getVersion(addr),
+            action, addr, tableIndex + BASE_TABLE_NUMBER);
+    if (runAndFree(NULL, cmd)) {
+        return -1;
+    }
+
+    modifyRuleCount(tableIndex, action);
+    return 0;
+}
+
+int SecondaryTableController::modifyLocalRoute(int tableIndex, const char *action,
+        const char *iface, const char *addr) {
+    char *cmd;
+
+    if (verifyTableIndex(tableIndex)) {
+        return -1;
+    }
+
+    modifyRuleCount(tableIndex, action); // some del's will fail as the iface is already gone.
+
+    asprintf(&cmd, "%s route %s %s dev %s table %d", IP_PATH, action, addr, iface,
+            tableIndex+BASE_TABLE_NUMBER);
+    return runAndFree(NULL, cmd);
+}
+
 int SecondaryTableController::runAndFree(SocketClient *cli, char *cmd) {
     int ret = 0;
     if (strlen(cmd) >= 255) {
-        ALOGE("ip command (%s) too long", cmd);
-        errno = E2BIG;
-        cli->sendMsg(ResponseCode::CommandSyntaxError, "Too long", true);
+        if (cli != NULL) {
+            ALOGE("ip command (%s) too long", cmd);
+            errno = E2BIG;
+            cli->sendMsg(ResponseCode::CommandSyntaxError, "Too long", true);
+        }
         free(cmd);
         return -1;
     }