am 551e5b47: am 553dc723: BandwidthController: validate interface / chain names

* commit '551e5b47a21294cf775f8effbb6f2bf34c664164':
  BandwidthController: validate interface / chain names
diff --git a/BandwidthController.cpp b/BandwidthController.cpp
index 6fad1e2..a7c2c2c 100644
--- a/BandwidthController.cpp
+++ b/BandwidthController.cpp
@@ -1147,10 +1147,12 @@
  * Parse the ptks and bytes out of:
  *   Chain natctrl_tether_counters (4 references)
  *       pkts      bytes target     prot opt in     out     source               destination
- *         26     2373 RETURN     all  --  wlan0  rmnet0  0.0.0.0/0            0.0.0.0/0            counter wlan0_rmnet0: 0 bytes
- *         27     2002 RETURN     all  --  rmnet0 wlan0   0.0.0.0/0            0.0.0.0/0            counter rmnet0_wlan0: 0 bytes
- *       1040   107471 RETURN     all  --  bt-pan rmnet0  0.0.0.0/0            0.0.0.0/0            counter bt-pan_rmnet0: 0 bytes
- *       1450  1708806 RETURN     all  --  rmnet0 bt-pan  0.0.0.0/0            0.0.0.0/0            counter rmnet0_bt-pan: 0 bytes
+ *         26     2373 RETURN     all  --  wlan0  rmnet0  0.0.0.0/0            0.0.0.0/0
+ *         27     2002 RETURN     all  --  rmnet0 wlan0   0.0.0.0/0            0.0.0.0/0
+ *       1040   107471 RETURN     all  --  bt-pan rmnet0  0.0.0.0/0            0.0.0.0/0
+ *       1450  1708806 RETURN     all  --  rmnet0 bt-pan  0.0.0.0/0            0.0.0.0/0
+ * It results in an error if invoked and no tethering counter rules exist. The constraint
+ * helps detect complete parsing failure.
  */
 int BandwidthController::parseForwardChainStats(SocketClient *cli, const TetherStats filter,
                                                 FILE *fp, std::string &extraProcessingInfo) {
@@ -1163,6 +1165,7 @@
     TetherStats stats;
     char *buffPtr;
     int64_t packets, bytes;
+    int statsFound = 0;
 
     bool filterPair = filter.intIface[0] && filter.extIface[0];
 
@@ -1238,14 +1241,18 @@
                 stats = filter;
             }
             free(msg);
+            statsFound++;
         }
     }
-    /* Successful if the last stats entry wasn't partial. */
-    if ((stats.rxBytes == -1) == (stats.txBytes == -1)) {
-        cli->sendMsg(ResponseCode::CommandOkay, "Tethering stats list completed", false);
-        return 0;
+
+    /* It is always an error to find only one side of the stats. */
+    /* It is an error to find nothing when not filtering. */
+    if (((stats.rxBytes == -1) != (stats.txBytes == -1)) ||
+        (!statsFound && !filterPair)) {
+        return -1;
     }
-    return -1;
+    cli->sendMsg(ResponseCode::CommandOkay, "Tethering stats list completed", false);
+    return 0;
 }
 
 char *BandwidthController::TetherStats::getStatsLine(void) const {
diff --git a/BandwidthController.h b/BandwidthController.h
index 8164e18..6b7b5d3 100644
--- a/BandwidthController.h
+++ b/BandwidthController.h
@@ -87,7 +87,8 @@
      * For all pairs, stats should have ifaceIn=ifaceOut="".
      * Sends out to the cli the single stat (TetheringStatsReluts) or a list of stats
      * (TetheringStatsListResult+CommandOkay).
-     * Error is to be handled on the outside
+     * Error is to be handled on the outside.
+     * It results in an error if invoked and no tethering counter rules exist.
      */
     int getTetherStats(SocketClient *cli, TetherStats &stats, std::string &extraProcessingInfo);
 
diff --git a/CommandListener.cpp b/CommandListener.cpp
index 84e9d5d..6ec2afc 100644
--- a/CommandListener.cpp
+++ b/CommandListener.cpp
@@ -1359,6 +1359,11 @@
         }
         tetherStats.intIface = argc > 2 ? argv[2] : "";
         tetherStats.extIface = argc > 3 ? argv[3] : "";
+        // No filtering requested and there are no interface pairs to lookup.
+        if (argc <= 2 && sNatCtrl->ifacePairList.empty()) {
+            cli->sendMsg(ResponseCode::CommandOkay, "Tethering stats list completed", false);
+            return 0;
+        }
         int rc = sBandwidthCtrl->getTetherStats(cli, tetherStats, extraProcessingInfo);
         if (rc) {
                 extraProcessingInfo.insert(0, "Failed to get tethering stats.\n");
diff --git a/IdletimerController.cpp b/IdletimerController.cpp
index 54b4edd..76b79a7 100644
--- a/IdletimerController.cpp
+++ b/IdletimerController.cpp
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-// #define LOG_NDEBUG 0
-
 /*
  * MODUS OPERANDI
  * --------------
@@ -95,6 +93,8 @@
  *
  */
 
+#define LOG_NDEBUG 0
+
 #include <stdlib.h>
 #include <errno.h>
 #include <sys/socket.h>
@@ -123,11 +123,27 @@
 }
 /* return 0 or non-zero */
 int IdletimerController::runIpxtablesCmd(int argc, const char **argv) {
-    int res;
+    int resIpv4, resIpv6;
 
-    res = android_fork_execvp(argc, (char **)argv, NULL, false, false);
-    ALOGV("runCmd() res=%d", res);
-    return res;
+    // Running for IPv4
+    argv[0] = IPTABLES_PATH;
+    resIpv4 = android_fork_execvp(argc, (char **)argv, NULL, false, false);
+
+    // Running for IPv6
+    argv[0] = IP6TABLES_PATH;
+    resIpv6 = android_fork_execvp(argc, (char **)argv, NULL, false, false);
+
+#if !LOG_NDEBUG
+    std::string full_cmd = argv[0];
+    argc--; argv++;
+    for (; argc; argc--, argv++) {
+        full_cmd += " ";
+        full_cmd += argv[0];
+    }
+    ALOGV("runCmd(%s) res_ipv4=%d, res_ipv6=%d", full_cmd.c_str(), resIpv4, resIpv6);
+#endif
+
+    return (resIpv4 == 0 && resIpv6 == 0) ? 0 : -1;
 }
 
 bool IdletimerController::setupIptablesHooks() {
@@ -137,7 +153,7 @@
 int IdletimerController::setDefaults() {
   int res;
   const char *cmd1[] = {
-      IPTABLES_PATH,
+      NULL, // To be filled inside runIpxtablesCmd
       "-t",
       "raw",
       "-F",
@@ -149,7 +165,7 @@
     return res;
 
   const char *cmd2[] = {
-      IPTABLES_PATH,
+      NULL, // To be filled inside runIpxtablesCmd
       "-t",
       "mangle",
       "-F",
@@ -179,7 +195,7 @@
   snprintf(timeout_str, sizeof(timeout_str), "%u", timeout);
 
   const char *cmd1[] = {
-      IPTABLES_PATH,
+      NULL, // To be filled inside runIpxtablesCmd
       "-t",
       "raw",
       (op == IptOpAdd) ? "-A" : "-D",
@@ -201,7 +217,7 @@
     return res;
 
   const char *cmd2[] = {
-      IPTABLES_PATH,
+      NULL, // To be filled inside runIpxtablesCmd
       "-t",
       "mangle",
       (op == IptOpAdd) ? "-A" : "-D",
diff --git a/NatController.cpp b/NatController.cpp
index dd5316a..fbf5f8a 100644
--- a/NatController.cpp
+++ b/NatController.cpp
@@ -98,6 +98,7 @@
                 return -1;
         }
     }
+    ifacePairList.clear();
 
     return 0;
 }
@@ -252,27 +253,32 @@
     return 0;
 }
 
+bool NatController::checkTetherCountingRuleExist(const char *pair_name) {
+    std::list<std::string>::iterator it;
+
+    for (it = ifacePairList.begin(); it != ifacePairList.end(); it++) {
+        if (*it == pair_name) {
+            /* We already have this counter */
+            return true;
+        }
+    }
+    return false;
+}
+
 int NatController::setTetherCountingRules(bool add, const char *intIface, const char *extIface) {
 
     /* We only ever add tethering quota rules so that they stick. */
     if (!add) {
         return 0;
     }
-    char *quota_name, *proc_path;
+    char *pair_name, *proc_path;
     int quota_fd;
-    asprintf(&quota_name, "%s_%s", intIface, extIface);
+    asprintf(&pair_name, "%s_%s", intIface, extIface);
 
-    asprintf(&proc_path, "/proc/net/xt_quota/%s", quota_name);
-    quota_fd = open(proc_path, O_RDONLY);
-    if (quota_fd >= 0) {
-        /* quota for iface pair already exists */
-        free(proc_path);
-        free(quota_name);
+    if (checkTetherCountingRuleExist(pair_name)) {
+        free(pair_name);
         return 0;
     }
-    close(quota_fd);
-    free(proc_path);
-
     const char *cmd2b[] = {
             IPTABLES_PATH,
             "-A",
@@ -281,32 +287,22 @@
             intIface,
             "-o",
             extIface,
-            "-m",
-            "quota2",
-            "--name",
-            quota_name,
-            "--grow",
             "-j",
           "RETURN"
     };
 
     if (runCmd(ARRAY_SIZE(cmd2b), cmd2b) && add) {
-        free(quota_name);
+        free(pair_name);
         return -1;
     }
-    free(quota_name);
+    ifacePairList.push_front(pair_name);
+    free(pair_name);
 
-    asprintf(&quota_name, "%s_%s", extIface, intIface);
-    asprintf(&proc_path, "/proc/net/xt_quota/%s", quota_name);
-    quota_fd = open(proc_path, O_RDONLY);
-    if (quota_fd >= 0) {
-        /* quota for iface pair already exists */
-        free(proc_path);
-        free(quota_name);
+    asprintf(&pair_name, "%s_%s", extIface, intIface);
+    if (checkTetherCountingRuleExist(pair_name)) {
+        free(pair_name);
         return 0;
     }
-    close(quota_fd);
-    free(proc_path);
 
     const char *cmd3b[] = {
             IPTABLES_PATH,
@@ -316,21 +312,17 @@
             extIface,
             "-o",
             intIface,
-            "-m",
-            "quota2",
-            "--name",
-            quota_name,
-            "--grow",
             "-j",
             "RETURN"
     };
 
     if (runCmd(ARRAY_SIZE(cmd3b), cmd3b) && add) {
         // unwind what's been done, but don't care about success - what more could we do?
-        free(quota_name);
+        free(pair_name);
         return -1;
     }
-    free(quota_name);
+    ifacePairList.push_front(pair_name);
+    free(pair_name);
     return 0;
 }
 
diff --git a/NatController.h b/NatController.h
index 5f45376..2912e4b 100644
--- a/NatController.h
+++ b/NatController.h
@@ -18,6 +18,8 @@
 #define _NAT_CONTROLLER_H
 
 #include <linux/in.h>
+#include <list>
+#include <string>
 
 class NetworkController;
 class SecondaryTableController;
@@ -36,11 +38,16 @@
     static const char* LOCAL_NAT_POSTROUTING;
     static const char* LOCAL_TETHER_COUNTERS_CHAIN;
 
+    // List of strings of interface pairs.
+    std::list<std::string> ifacePairList;
+
 private:
     int natCount;
     SecondaryTableController *mSecondaryTableCtrl;
     NetworkController *mNetCtrl;
 
+    bool checkTetherCountingRuleExist(const char *pair_name);
+
     int setDefaults();
     int runCmd(int argc, const char **argv);
     bool checkInterface(const char *iface);
diff --git a/NetlinkHandler.cpp b/NetlinkHandler.cpp
index 534f386..9c2984f 100644
--- a/NetlinkHandler.cpp
+++ b/NetlinkHandler.cpp
@@ -91,14 +91,11 @@
 
     } else if (!strcmp(subsys, "xt_idletimer")) {
         int action = evt->getAction();
-        const char *label = evt->findParam("LABEL");
+        const char *label = evt->findParam("INTERFACE");
         const char *state = evt->findParam("STATE");
-        // if no LABEL, use INTERFACE instead
-        if (label == NULL) {
-            label = evt->findParam("INTERFACE");
-        }
+        const char *timestamp = evt->findParam("TIME_NS");
         if (state)
-            notifyInterfaceClassActivity(label, !strcmp("active", state));
+            notifyInterfaceClassActivity(label, !strcmp("active", state), timestamp);
 
 #if !LOG_NDEBUG
     } else if (strcmp(subsys, "platform") && strcmp(subsys, "backlight")) {
@@ -144,9 +141,13 @@
 }
 
 void NetlinkHandler::notifyInterfaceClassActivity(const char *name,
-                                                  bool isActive) {
-    notify(ResponseCode::InterfaceClassActivity,
+                                                  bool isActive, const char *timestamp) {
+    if (timestamp == NULL)
+        notify(ResponseCode::InterfaceClassActivity,
            "IfaceClass %s %s", isActive ? "active" : "idle", name);
+    else
+        notify(ResponseCode::InterfaceClassActivity,
+           "IfaceClass %s %s %s", isActive ? "active" : "idle", name, timestamp);
 }
 
 void NetlinkHandler::notifyAddressChanged(int action, const char *addr,
diff --git a/NetlinkHandler.h b/NetlinkHandler.h
index 94b7282..a5c5b6b 100644
--- a/NetlinkHandler.h
+++ b/NetlinkHandler.h
@@ -39,7 +39,8 @@
     void notifyInterfaceChanged(const char *name, bool isUp);
     void notifyInterfaceLinkChanged(const char *name, bool isUp);
     void notifyQuotaLimitReached(const char *name, const char *iface);
-    void notifyInterfaceClassActivity(const char *name, bool isActive);
+    void notifyInterfaceClassActivity(const char *name, bool isActive,
+                                      const char *timestamp);
     void notifyAddressChanged(int action, const char *addr, const char *iface,
                               const char *flags, const char *scope);
     void notifyInterfaceDnsServers(const char *iface, const char *lifetime,
diff --git a/SoftapController.cpp b/SoftapController.cpp
index 825a376..7d5da95 100644
--- a/SoftapController.cpp
+++ b/SoftapController.cpp
@@ -144,7 +144,7 @@
     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);
+            asprintf(&fbuf, "%swpa=3\nwpa_pairwise=TKIP CCMP\nwpa_psk=%s\n", wbuf, 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);