* 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) {
TetherStats stats;
char *buffPtr;
int64_t packets, bytes;
+ int statsFound = 0;
bool filterPair = filter.intIface[0] && filter.extIface[0];
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 {
* 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);
}
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");
return -1;
}
}
+ ifacePairList.clear();
return 0;
}
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("a_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);
+ asprintf(&pair_name, "%s_%s", intIface, extIface);
+
+ if (checkTetherCountingRuleExist(pair_name)) {
+ free(pair_name);
return 0;
}
- close(quota_fd);
- free(proc_path);
-
const char *cmd2b[] = {
IPTABLES_PATH,
"-A",
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);
-
- asprintf("a_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);
+ ifacePairList.push_front(pair_name);
+ free(pair_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,
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;
}
#define _NAT_CONTROLLER_H
#include <linux/in.h>
+#include <list>
#include "SecondaryTableController.h"
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 *secondaryTableCtrl;
+ bool checkTetherCountingRuleExist(const char *pair_name);
+
int setDefaults();
int runCmd(int argc, const char **argv);
bool checkInterface(const char *iface);