blob: c70fc131295f5bfae34460610f40adbc6f674d12 [file] [log] [blame]
JP Abgrall4a5f5ca2011-06-15 18:37:39 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
JP Abgralle4788732013-07-02 20:28:45 -070017// #define LOG_NDEBUG 0
JP Abgralldb7da582011-09-18 12:57:32 -070018
19/*
20 * The CommandListener, FrameworkListener don't allow for
21 * multiple calls in parallel to reach the BandwidthController.
22 * If they ever were to allow it, then netd/ would need some tweaking.
23 */
24
JP Abgrall8a932722011-07-13 19:17:35 -070025#include <errno.h>
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070026#include <fcntl.h>
JP Abgralldb7da582011-09-18 12:57:32 -070027#include <stdio.h>
JP Abgrall8a932722011-07-13 19:17:35 -070028#include <stdlib.h>
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070029#include <string.h>
30
Matthew Leach2a54d962013-01-14 15:07:12 +000031#define __STDC_FORMAT_MACROS 1
32#include <inttypes.h>
33
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070034#include <sys/socket.h>
35#include <sys/stat.h>
36#include <sys/types.h>
37#include <sys/wait.h>
38
39#include <linux/netlink.h>
40#include <linux/rtnetlink.h>
41#include <linux/pkt_sched.h>
42
43#define LOG_TAG "BandwidthController"
44#include <cutils/log.h>
45#include <cutils/properties.h>
Rom Lemarchand14150212013-01-24 10:01:04 -080046#include <logwrap/logwrap.h>
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070047
JP Abgrall0031cea2012-04-17 16:38:23 -070048#include "NetdConstants.h"
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070049#include "BandwidthController.h"
JP Abgrallbaeccc42013-06-25 09:44:10 -070050#include "NatController.h" /* For LOCAL_TETHER_COUNTERS_CHAIN */
51#include "ResponseCode.h"
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070052
JP Abgralldb7da582011-09-18 12:57:32 -070053/* Alphabetical */
Matthew Leach2a54d962013-01-14 15:07:12 +000054#define ALERT_IPT_TEMPLATE "%s %s -m quota2 ! --quota %"PRId64" --name %s"
JP Abgrallc6c67342011-10-07 16:28:54 -070055const char BandwidthController::ALERT_GLOBAL_NAME[] = "globalAlert";
Jeff Sharkey8e188ed2012-07-12 18:32:03 -070056const char* BandwidthController::LOCAL_INPUT = "bw_INPUT";
57const char* BandwidthController::LOCAL_FORWARD = "bw_FORWARD";
58const char* BandwidthController::LOCAL_OUTPUT = "bw_OUTPUT";
59const char* BandwidthController::LOCAL_RAW_PREROUTING = "bw_raw_PREROUTING";
60const char* BandwidthController::LOCAL_MANGLE_POSTROUTING = "bw_mangle_POSTROUTING";
JP Abgralldb7da582011-09-18 12:57:32 -070061const int BandwidthController::MAX_CMD_ARGS = 32;
62const int BandwidthController::MAX_CMD_LEN = 1024;
63const int BandwidthController::MAX_IFACENAME_LEN = 64;
64const int BandwidthController::MAX_IPT_OUTPUT_LINE_LEN = 256;
65
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070066/**
67 * Some comments about the rules:
68 * * Ordering
69 * - when an interface is marked as costly it should be INSERTED into the INPUT/OUTPUT chains.
JP Abgrall29e8de22012-05-03 12:52:15 -070070 * E.g. "-I bw_INPUT -i rmnet0 --jump costly"
JP Abgrall7e51cde2013-07-03 13:33:05 -070071 * - quota'd rules in the costly chain should be before bw_penalty_box lookups.
72 * - bw_happy_box rejects everything by default.
JP Abgrall29e8de22012-05-03 12:52:15 -070073 * - the qtaguid counting is done at the end of the bw_INPUT/bw_OUTPUT user chains.
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070074 *
75 * * global quota vs per interface quota
76 * - global quota for all costly interfaces uses a single costly chain:
77 * . initial rules
JP Abgrall7e51cde2013-07-03 13:33:05 -070078 * iptables -N bw_costly_shared
79 * iptables -I bw_INPUT -i iface0 --jump bw_costly_shared
80 * iptables -I bw_OUTPUT -o iface0 --jump bw_costly_shared
81 * iptables -I bw_costly_shared -m quota \! --quota 500000 \
JP Abgrallbfa74662011-06-29 19:23:04 -070082 * --jump REJECT --reject-with icmp-net-prohibited
JP Abgrall7e51cde2013-07-03 13:33:05 -070083 * iptables -A bw_costly_shared --jump bw_penalty_box
JP Abgralle4788732013-07-02 20:28:45 -070084 * If the happy box is enabled,
JP Abgrall7e51cde2013-07-03 13:33:05 -070085 * iptables -A bw_penalty_box --jump bw_happy_box
JP Abgrall8a932722011-07-13 19:17:35 -070086 *
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070087 * . adding a new iface to this, E.g.:
JP Abgrall7e51cde2013-07-03 13:33:05 -070088 * iptables -I bw_INPUT -i iface1 --jump bw_costly_shared
89 * iptables -I bw_OUTPUT -o iface1 --jump bw_costly_shared
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070090 *
91 * - quota per interface. This is achieve by having "costly" chains per quota.
92 * E.g. adding a new costly interface iface0 with its own quota:
JP Abgrall7e51cde2013-07-03 13:33:05 -070093 * iptables -N bw_costly_iface0
94 * iptables -I bw_INPUT -i iface0 --jump bw_costly_iface0
95 * iptables -I bw_OUTPUT -o iface0 --jump bw_costly_iface0
96 * iptables -A bw_costly_iface0 -m quota \! --quota 500000 \
JP Abgralle4788732013-07-02 20:28:45 -070097 * --jump REJECT --reject-with icmp-port-unreachable
JP Abgrall7e51cde2013-07-03 13:33:05 -070098 * iptables -A bw_costly_iface0 --jump bw_penalty_box
JP Abgrall4a5f5ca2011-06-15 18:37:39 -070099 *
JP Abgrall7e51cde2013-07-03 13:33:05 -0700100 * * bw_penalty_box handling:
101 * - only one bw_penalty_box for all interfaces
102 * E.g Adding an app, it has to preserve the appened bw_happy_box, so "-I":
103 * iptables -I bw_penalty_box -m owner --uid-owner app_3 \
JP Abgralle4788732013-07-02 20:28:45 -0700104 * --jump REJECT --reject-with icmp-port-unreachable
105 *
JP Abgrall7e51cde2013-07-03 13:33:05 -0700106 * * bw_happy_box handling:
107 * - The bw_happy_box goes at the end of the penalty box.
JP Abgralle4788732013-07-02 20:28:45 -0700108 * E.g Adding a happy app,
JP Abgrall7e51cde2013-07-03 13:33:05 -0700109 * iptables -I bw_happy_box -m owner --uid-owner app_3 \
JP Abgralle4788732013-07-02 20:28:45 -0700110 * --jump RETURN
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700111 */
JP Abgrall0031cea2012-04-17 16:38:23 -0700112const char *BandwidthController::IPT_FLUSH_COMMANDS[] = {
113 /*
114 * Cleanup rules.
JP Abgrall7e51cde2013-07-03 13:33:05 -0700115 * Should normally include bw_costly_<iface>, but we rely on the way they are setup
JP Abgrall0031cea2012-04-17 16:38:23 -0700116 * to allow coexistance.
JP Abgrall39f8f242011-06-29 19:21:58 -0700117 */
JP Abgrall0031cea2012-04-17 16:38:23 -0700118 "-F bw_INPUT",
119 "-F bw_OUTPUT",
120 "-F bw_FORWARD",
JP Abgrall7e51cde2013-07-03 13:33:05 -0700121 "-F bw_happy_box",
122 "-F bw_penalty_box",
123 "-F bw_costly_shared",
JP Abgrallf66d6e92012-04-27 00:22:57 -0700124
125 "-t raw -F bw_raw_PREROUTING",
126 "-t mangle -F bw_mangle_POSTROUTING",
JP Abgrall0031cea2012-04-17 16:38:23 -0700127};
128
129/* The cleanup commands assume flushing has been done. */
130const char *BandwidthController::IPT_CLEANUP_COMMANDS[] = {
JP Abgrall7e51cde2013-07-03 13:33:05 -0700131 "-X bw_happy_box",
132 "-X bw_penalty_box",
133 "-X bw_costly_shared",
JP Abgrall0dad7c22011-06-24 11:58:14 -0700134};
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700135
JP Abgralldb7da582011-09-18 12:57:32 -0700136const char *BandwidthController::IPT_SETUP_COMMANDS[] = {
JP Abgrall7e51cde2013-07-03 13:33:05 -0700137 "-N bw_happy_box",
138 "-N bw_penalty_box",
139 "-N bw_costly_shared",
JP Abgrall0dad7c22011-06-24 11:58:14 -0700140};
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700141
JP Abgralldb7da582011-09-18 12:57:32 -0700142const char *BandwidthController::IPT_BASIC_ACCOUNTING_COMMANDS[] = {
JP Abgrall0031cea2012-04-17 16:38:23 -0700143 "-A bw_INPUT -m owner --socket-exists", /* This is a tracking rule. */
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700144
JP Abgrall0031cea2012-04-17 16:38:23 -0700145 "-A bw_OUTPUT -m owner --socket-exists", /* This is a tracking rule. */
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700146
JP Abgrall7e51cde2013-07-03 13:33:05 -0700147 "-A bw_costly_shared --jump bw_penalty_box",
JP Abgrallf66d6e92012-04-27 00:22:57 -0700148
JP Abgrall92009c82013-02-06 18:01:24 -0800149 "-t raw -A bw_raw_PREROUTING -m owner --socket-exists", /* This is a tracking rule. */
150 "-t mangle -A bw_mangle_POSTROUTING -m owner --socket-exists", /* This is a tracking rule. */
JP Abgrall0dad7c22011-06-24 11:58:14 -0700151};
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700152
153BandwidthController::BandwidthController(void) {
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700154}
155
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700156int BandwidthController::runIpxtablesCmd(const char *cmd, IptJumpOp jumpHandling,
JP Abgrallad729ac2012-04-24 23:27:44 -0700157 IptFailureLog failureHandling) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700158 int res = 0;
JP Abgrall8a932722011-07-13 19:17:35 -0700159
Steve Block3fb42e02011-10-20 11:55:56 +0100160 ALOGV("runIpxtablesCmd(cmd=%s)", cmd);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700161 res |= runIptablesCmd(cmd, jumpHandling, IptIpV4, failureHandling);
162 res |= runIptablesCmd(cmd, jumpHandling, IptIpV6, failureHandling);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700163 return res;
164}
165
JP Abgrall26e0d492011-06-24 19:21:51 -0700166int BandwidthController::StrncpyAndCheck(char *buffer, const char *src, size_t buffSize) {
167
168 memset(buffer, '\0', buffSize); // strncpy() is not filling leftover with '\0'
169 strncpy(buffer, src, buffSize);
170 return buffer[buffSize - 1];
171}
172
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700173int BandwidthController::runIptablesCmd(const char *cmd, IptJumpOp jumpHandling,
JP Abgrallad729ac2012-04-24 23:27:44 -0700174 IptIpVer iptVer, IptFailureLog failureHandling) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700175 char buffer[MAX_CMD_LEN];
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700176 const char *argv[MAX_CMD_ARGS];
JP Abgrall26e0d492011-06-24 19:21:51 -0700177 int argc = 0;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700178 char *next = buffer;
179 char *tmp;
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700180 int res;
Rom Lemarchand14150212013-01-24 10:01:04 -0800181 int status = 0;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700182
JP Abgrall0dad7c22011-06-24 11:58:14 -0700183 std::string fullCmd = cmd;
JP Abgrall26e0d492011-06-24 19:21:51 -0700184
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700185 switch (jumpHandling) {
186 case IptJumpReject:
JP Abgrall340d5cc2013-06-28 17:06:00 -0700187 /*
188 * Must be carefull what one rejects with, as uper layer protocols will just
189 * keep on hammering the device until the number of retries are done.
190 * For port-unreachable (default), TCP should consider as an abort (RFC1122).
191 */
192 fullCmd += " --jump REJECT";
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700193 break;
194 case IptJumpReturn:
195 fullCmd += " --jump RETURN";
196 break;
197 case IptJumpNoAdd:
198 break;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700199 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700200
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700201 fullCmd.insert(0, " ");
202 fullCmd.insert(0, iptVer == IptIpV4 ? IPTABLES_PATH : IP6TABLES_PATH);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700203
Rom Lemarchand14150212013-01-24 10:01:04 -0800204 if (StrncpyAndCheck(buffer, fullCmd.c_str(), sizeof(buffer))) {
205 ALOGE("iptables command too long");
206 return -1;
207 }
208
209 argc = 0;
210 while ((tmp = strsep(&next, " "))) {
211 argv[argc++] = tmp;
212 if (argc >= MAX_CMD_ARGS) {
213 ALOGE("iptables argument overflow");
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700214 return -1;
215 }
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700216 }
Rom Lemarchand14150212013-01-24 10:01:04 -0800217
218 argv[argc] = NULL;
219 res = android_fork_execvp(argc, (char **)argv, &status, false,
220 failureHandling == IptFailShow);
JP Abgrallc8dc63b2013-02-13 16:30:00 -0800221 res = res || !WIFEXITED(status) || WEXITSTATUS(status);
222 if (res && failureHandling == IptFailShow) {
223 ALOGE("runIptablesCmd(): res=%d status=%d failed %s", res, status,
224 fullCmd.c_str());
JP Abgrall11b4e9b2011-08-11 15:34:49 -0700225 }
226 return res;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700227}
228
JP Abgrall0e540ec2013-08-26 15:13:10 -0700229void BandwidthController::flushCleanTables(bool doClean) {
230 /* Flush and remove the bw_costly_<iface> tables */
231 flushExistingCostlyTables(doClean);
JP Abgrall0031cea2012-04-17 16:38:23 -0700232
233 /* Some of the initialCommands are allowed to fail */
234 runCommands(sizeof(IPT_FLUSH_COMMANDS) / sizeof(char*),
235 IPT_FLUSH_COMMANDS, RunCmdFailureOk);
236
JP Abgrall0e540ec2013-08-26 15:13:10 -0700237 if (doClean) {
238 runCommands(sizeof(IPT_CLEANUP_COMMANDS) / sizeof(char*),
239 IPT_CLEANUP_COMMANDS, RunCmdFailureOk);
240 }
241}
JP Abgrall0031cea2012-04-17 16:38:23 -0700242
JP Abgrall0e540ec2013-08-26 15:13:10 -0700243int BandwidthController::setupIptablesHooks(void) {
244
245 /* flush+clean is allowed to fail */
246 flushCleanTables(true);
JP Abgrall0031cea2012-04-17 16:38:23 -0700247 runCommands(sizeof(IPT_SETUP_COMMANDS) / sizeof(char*),
248 IPT_SETUP_COMMANDS, RunCmdFailureBad);
249
250 return 0;
JP Abgrall0031cea2012-04-17 16:38:23 -0700251}
252
253int BandwidthController::enableBandwidthControl(bool force) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700254 int res;
JP Abgrall0031cea2012-04-17 16:38:23 -0700255 char value[PROPERTY_VALUE_MAX];
256
257 if (!force) {
258 property_get("persist.bandwidth.enable", value, "1");
259 if (!strcmp(value, "0"))
260 return 0;
261 }
JP Abgrall8a932722011-07-13 19:17:35 -0700262
JP Abgralldb7da582011-09-18 12:57:32 -0700263 /* Let's pretend we started from scratch ... */
JP Abgrall8a932722011-07-13 19:17:35 -0700264 sharedQuotaIfaces.clear();
265 quotaIfaces.clear();
266 naughtyAppUids.clear();
JP Abgralle4788732013-07-02 20:28:45 -0700267 niceAppUids.clear();
JP Abgralldb7da582011-09-18 12:57:32 -0700268 globalAlertBytes = 0;
JP Abgrallc6c67342011-10-07 16:28:54 -0700269 globalAlertTetherCount = 0;
JP Abgralldb7da582011-09-18 12:57:32 -0700270 sharedQuotaBytes = sharedAlertBytes = 0;
271
JP Abgrall0e540ec2013-08-26 15:13:10 -0700272 flushCleanTables(false);
273 res = runCommands(sizeof(IPT_BASIC_ACCOUNTING_COMMANDS) / sizeof(char*),
JP Abgralldb7da582011-09-18 12:57:32 -0700274 IPT_BASIC_ACCOUNTING_COMMANDS, RunCmdFailureBad);
JP Abgrall8a932722011-07-13 19:17:35 -0700275
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700276 return res;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700277
278}
279
280int BandwidthController::disableBandwidthControl(void) {
JP Abgrall0e540ec2013-08-26 15:13:10 -0700281
282 flushCleanTables(false);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700283 return 0;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700284}
285
JP Abgrall8a932722011-07-13 19:17:35 -0700286int BandwidthController::runCommands(int numCommands, const char *commands[],
287 RunCmdErrHandling cmdErrHandling) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700288 int res = 0;
JP Abgrallad729ac2012-04-24 23:27:44 -0700289 IptFailureLog failureLogging = IptFailShow;
290 if (cmdErrHandling == RunCmdFailureOk) {
291 failureLogging = IptFailHide;
292 }
Steve Block3fb42e02011-10-20 11:55:56 +0100293 ALOGV("runCommands(): %d commands", numCommands);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700294 for (int cmdNum = 0; cmdNum < numCommands; cmdNum++) {
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700295 res = runIpxtablesCmd(commands[cmdNum], IptJumpNoAdd, failureLogging);
JP Abgrall0031cea2012-04-17 16:38:23 -0700296 if (res && cmdErrHandling != RunCmdFailureOk)
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700297 return res;
298 }
JP Abgrall0031cea2012-04-17 16:38:23 -0700299 return 0;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700300}
301
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700302std::string BandwidthController::makeIptablesSpecialAppCmd(IptOp op, int uid, const char *chain) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700303 std::string res;
JP Abgrall8a932722011-07-13 19:17:35 -0700304 char *buff;
305 const char *opFlag;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700306
307 switch (op) {
JP Abgrall8a932722011-07-13 19:17:35 -0700308 case IptOpInsert:
309 opFlag = "-I";
310 break;
JP Abgrall109899b2013-02-12 19:20:13 -0800311 case IptOpAppend:
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700312 ALOGE("Append op not supported for %s uids", chain);
313 res = "";
314 return res;
JP Abgrall109899b2013-02-12 19:20:13 -0800315 break;
JP Abgrall8a932722011-07-13 19:17:35 -0700316 case IptOpReplace:
317 opFlag = "-R";
318 break;
319 default:
320 case IptOpDelete:
321 opFlag = "-D";
322 break;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700323 }
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700324 asprintf(&buff, "%s %s -m owner --uid-owner %d", opFlag, chain, uid);
JP Abgrall8a932722011-07-13 19:17:35 -0700325 res = buff;
326 free(buff);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700327 return res;
328}
329
JP Abgralle4788732013-07-02 20:28:45 -0700330int BandwidthController::enableHappyBox(void) {
331 char cmd[MAX_CMD_LEN];
332 int res = 0;
333
334 /*
335 * We tentatively delete before adding, which helps recovering
336 * from bad states (e.g. netd died).
337 */
338
339 /* Should not exist, but ignore result if already there. */
JP Abgrall7e51cde2013-07-03 13:33:05 -0700340 snprintf(cmd, sizeof(cmd), "-N bw_happy_box");
JP Abgralle4788732013-07-02 20:28:45 -0700341 runIpxtablesCmd(cmd, IptJumpNoAdd);
342
343 /* Should be empty, but clear in case something was wrong. */
344 niceAppUids.clear();
JP Abgrall7e51cde2013-07-03 13:33:05 -0700345 snprintf(cmd, sizeof(cmd), "-F bw_happy_box");
JP Abgralle4788732013-07-02 20:28:45 -0700346 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
347
JP Abgrall7e51cde2013-07-03 13:33:05 -0700348 snprintf(cmd, sizeof(cmd), "-D bw_penalty_box -j bw_happy_box");
JP Abgralle4788732013-07-02 20:28:45 -0700349 runIpxtablesCmd(cmd, IptJumpNoAdd);
JP Abgrall7e51cde2013-07-03 13:33:05 -0700350 snprintf(cmd, sizeof(cmd), "-A bw_penalty_box -j bw_happy_box");
JP Abgralle4788732013-07-02 20:28:45 -0700351 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
352
353 /* Reject. Defaulting to prot-unreachable */
JP Abgrall7e51cde2013-07-03 13:33:05 -0700354 snprintf(cmd, sizeof(cmd), "-D bw_happy_box -j REJECT");
JP Abgralle4788732013-07-02 20:28:45 -0700355 runIpxtablesCmd(cmd, IptJumpNoAdd);
JP Abgrall7e51cde2013-07-03 13:33:05 -0700356 snprintf(cmd, sizeof(cmd), "-A bw_happy_box -j REJECT");
JP Abgralle4788732013-07-02 20:28:45 -0700357 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
358
359 return res;
360}
361
362int BandwidthController::disableHappyBox(void) {
363 char cmd[MAX_CMD_LEN];
364
365 /* Best effort */
JP Abgrall7e51cde2013-07-03 13:33:05 -0700366 snprintf(cmd, sizeof(cmd), "-D bw_penalty_box -j bw_happy_box");
JP Abgralle4788732013-07-02 20:28:45 -0700367 runIpxtablesCmd(cmd, IptJumpNoAdd);
368 niceAppUids.clear();
JP Abgrall7e51cde2013-07-03 13:33:05 -0700369 snprintf(cmd, sizeof(cmd), "-F bw_happy_box");
JP Abgralle4788732013-07-02 20:28:45 -0700370 runIpxtablesCmd(cmd, IptJumpNoAdd);
JP Abgrall7e51cde2013-07-03 13:33:05 -0700371 snprintf(cmd, sizeof(cmd), "-X bw_happy_box");
JP Abgralle4788732013-07-02 20:28:45 -0700372 runIpxtablesCmd(cmd, IptJumpNoAdd);
373
374 return 0;
375}
376
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700377int BandwidthController::addNaughtyApps(int numUids, char *appUids[]) {
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700378 return manipulateNaughtyApps(numUids, appUids, SpecialAppOpAdd);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700379}
380
381int BandwidthController::removeNaughtyApps(int numUids, char *appUids[]) {
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700382 return manipulateNaughtyApps(numUids, appUids, SpecialAppOpRemove);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700383}
384
JP Abgralle4788732013-07-02 20:28:45 -0700385int BandwidthController::addNiceApps(int numUids, char *appUids[]) {
386 return manipulateNiceApps(numUids, appUids, SpecialAppOpAdd);
387}
388
389int BandwidthController::removeNiceApps(int numUids, char *appUids[]) {
390 return manipulateNiceApps(numUids, appUids, SpecialAppOpRemove);
391}
392
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700393int BandwidthController::manipulateNaughtyApps(int numUids, char *appStrUids[], SpecialAppOp appOp) {
JP Abgrall7e51cde2013-07-03 13:33:05 -0700394 return manipulateSpecialApps(numUids, appStrUids, "bw_penalty_box", naughtyAppUids, IptJumpReject, appOp);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700395}
396
JP Abgralle4788732013-07-02 20:28:45 -0700397int BandwidthController::manipulateNiceApps(int numUids, char *appStrUids[], SpecialAppOp appOp) {
JP Abgrall7e51cde2013-07-03 13:33:05 -0700398 return manipulateSpecialApps(numUids, appStrUids, "bw_happy_box", niceAppUids, IptJumpReturn, appOp);
JP Abgralle4788732013-07-02 20:28:45 -0700399}
400
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700401
402int BandwidthController::manipulateSpecialApps(int numUids, char *appStrUids[],
403 const char *chain,
404 std::list<int /*appUid*/> &specialAppUids,
405 IptJumpOp jumpHandling, SpecialAppOp appOp) {
406
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700407 char cmd[MAX_CMD_LEN];
408 int uidNum;
JP Abgrall26e0d492011-06-24 19:21:51 -0700409 const char *failLogTemplate;
410 IptOp op;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700411 int appUids[numUids];
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700412 std::string iptCmd;
JP Abgrallb1d24092012-04-27 01:02:31 -0700413 std::list<int /*uid*/>::iterator it;
JP Abgrall8a932722011-07-13 19:17:35 -0700414
JP Abgrall26e0d492011-06-24 19:21:51 -0700415 switch (appOp) {
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700416 case SpecialAppOpAdd:
JP Abgrall8a932722011-07-13 19:17:35 -0700417 op = IptOpInsert;
JP Abgrallaf476f72013-07-03 12:23:55 -0700418 failLogTemplate = "Failed to add app uid %s(%d) to %s.";
JP Abgrall8a932722011-07-13 19:17:35 -0700419 break;
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700420 case SpecialAppOpRemove:
JP Abgrall8a932722011-07-13 19:17:35 -0700421 op = IptOpDelete;
JP Abgrallaf476f72013-07-03 12:23:55 -0700422 failLogTemplate = "Failed to delete app uid %s(%d) from %s box.";
JP Abgrall8a932722011-07-13 19:17:35 -0700423 break;
JP Abgrall0031cea2012-04-17 16:38:23 -0700424 default:
425 ALOGE("Unexpected app Op %d", appOp);
426 return -1;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700427 }
428
429 for (uidNum = 0; uidNum < numUids; uidNum++) {
JP Abgrallaf476f72013-07-03 12:23:55 -0700430 char *end;
431 appUids[uidNum] = strtoul(appStrUids[uidNum], &end, 0);
432 if (*end || !*appStrUids[uidNum]) {
433 ALOGE(failLogTemplate, appStrUids[uidNum], appUids[uidNum], chain);
JP Abgrall26e0d492011-06-24 19:21:51 -0700434 goto fail_parse;
435 }
436 }
JP Abgrall26e0d492011-06-24 19:21:51 -0700437
438 for (uidNum = 0; uidNum < numUids; uidNum++) {
JP Abgrallb1d24092012-04-27 01:02:31 -0700439 int uid = appUids[uidNum];
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700440 for (it = specialAppUids.begin(); it != specialAppUids.end(); it++) {
JP Abgrallb1d24092012-04-27 01:02:31 -0700441 if (*it == uid)
442 break;
443 }
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700444 bool found = (it != specialAppUids.end());
JP Abgrallb1d24092012-04-27 01:02:31 -0700445
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700446 if (appOp == SpecialAppOpRemove) {
JP Abgrallb1d24092012-04-27 01:02:31 -0700447 if (!found) {
448 ALOGE("No such appUid %d to remove", uid);
449 return -1;
450 }
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700451 specialAppUids.erase(it);
JP Abgrallb1d24092012-04-27 01:02:31 -0700452 } else {
453 if (found) {
454 ALOGE("appUid %d exists already", uid);
455 return -1;
456 }
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700457 specialAppUids.push_front(uid);
JP Abgrallb1d24092012-04-27 01:02:31 -0700458 }
459
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700460 iptCmd = makeIptablesSpecialAppCmd(op, uid, chain);
461 if (runIpxtablesCmd(iptCmd.c_str(), jumpHandling)) {
JP Abgrallaf476f72013-07-03 12:23:55 -0700462 ALOGE(failLogTemplate, appStrUids[uidNum], uid, chain);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700463 goto fail_with_uidNum;
464 }
465 }
466 return 0;
467
JP Abgrall26e0d492011-06-24 19:21:51 -0700468fail_with_uidNum:
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700469 /* Try to remove the uid that failed in any case*/
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700470 iptCmd = makeIptablesSpecialAppCmd(IptOpDelete, appUids[uidNum], chain);
471 runIpxtablesCmd(iptCmd.c_str(), jumpHandling);
JP Abgrall26e0d492011-06-24 19:21:51 -0700472fail_parse:
473 return -1;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700474}
475
JP Abgrall26e0d492011-06-24 19:21:51 -0700476std::string BandwidthController::makeIptablesQuotaCmd(IptOp op, const char *costName, int64_t quota) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700477 std::string res;
JP Abgrall8a932722011-07-13 19:17:35 -0700478 char *buff;
479 const char *opFlag;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700480
Matthew Leach2a54d962013-01-14 15:07:12 +0000481 ALOGV("makeIptablesQuotaCmd(%d, %"PRId64")", op, quota);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700482
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700483 switch (op) {
JP Abgrall8a932722011-07-13 19:17:35 -0700484 case IptOpInsert:
485 opFlag = "-I";
486 break;
JP Abgrall109899b2013-02-12 19:20:13 -0800487 case IptOpAppend:
488 opFlag = "-A";
489 break;
JP Abgrall8a932722011-07-13 19:17:35 -0700490 case IptOpReplace:
491 opFlag = "-R";
492 break;
493 default:
494 case IptOpDelete:
495 opFlag = "-D";
496 break;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700497 }
JP Abgrall8a932722011-07-13 19:17:35 -0700498
JP Abgrallbfa74662011-06-29 19:23:04 -0700499 // The requried IP version specific --jump REJECT ... will be added later.
Matthew Leach2a54d962013-01-14 15:07:12 +0000500 asprintf(&buff, "%s bw_costly_%s -m quota2 ! --quota %"PRId64" --name %s", opFlag, costName, quota,
JP Abgrall8a932722011-07-13 19:17:35 -0700501 costName);
502 res = buff;
503 free(buff);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700504 return res;
505}
506
JP Abgrall26e0d492011-06-24 19:21:51 -0700507int BandwidthController::prepCostlyIface(const char *ifn, QuotaType quotaType) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700508 char cmd[MAX_CMD_LEN];
JP Abgrall0031cea2012-04-17 16:38:23 -0700509 int res = 0, res1, res2;
JP Abgrall8a932722011-07-13 19:17:35 -0700510 int ruleInsertPos = 1;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700511 std::string costString;
512 const char *costCString;
513
JP Abgrall0dad7c22011-06-24 11:58:14 -0700514 /* The "-N costly" is created upfront, no need to handle it here. */
JP Abgrall26e0d492011-06-24 19:21:51 -0700515 switch (quotaType) {
516 case QuotaUnique:
JP Abgrall7e51cde2013-07-03 13:33:05 -0700517 costString = "bw_costly_";
JP Abgrall0dad7c22011-06-24 11:58:14 -0700518 costString += ifn;
519 costCString = costString.c_str();
JP Abgrall0031cea2012-04-17 16:38:23 -0700520 /*
JP Abgrall7e51cde2013-07-03 13:33:05 -0700521 * Flush the bw_costly_<iface> is allowed to fail in case it didn't exist.
JP Abgrall0031cea2012-04-17 16:38:23 -0700522 * Creating a new one is allowed to fail in case it existed.
523 * This helps with netd restarts.
524 */
525 snprintf(cmd, sizeof(cmd), "-F %s", costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700526 res1 = runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700527 snprintf(cmd, sizeof(cmd), "-N %s", costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700528 res2 = runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
JP Abgrall0031cea2012-04-17 16:38:23 -0700529 res = (res1 && res2) || (!res1 && !res2);
530
JP Abgrall7e51cde2013-07-03 13:33:05 -0700531 snprintf(cmd, sizeof(cmd), "-A %s -j bw_penalty_box", costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700532 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
JP Abgrall26e0d492011-06-24 19:21:51 -0700533 break;
534 case QuotaShared:
JP Abgrall7e51cde2013-07-03 13:33:05 -0700535 costCString = "bw_costly_shared";
JP Abgrall26e0d492011-06-24 19:21:51 -0700536 break;
JP Abgrall0031cea2012-04-17 16:38:23 -0700537 default:
538 ALOGE("Unexpected quotatype %d", quotaType);
539 return -1;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700540 }
541
JP Abgrall8a932722011-07-13 19:17:35 -0700542 if (globalAlertBytes) {
543 /* The alert rule comes 1st */
544 ruleInsertPos = 2;
545 }
JP Abgrall0031cea2012-04-17 16:38:23 -0700546
547 snprintf(cmd, sizeof(cmd), "-D bw_INPUT -i %s --jump %s", ifn, costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700548 runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
JP Abgrall0031cea2012-04-17 16:38:23 -0700549
550 snprintf(cmd, sizeof(cmd), "-I bw_INPUT %d -i %s --jump %s", ruleInsertPos, ifn, costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700551 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
JP Abgrall0031cea2012-04-17 16:38:23 -0700552
553 snprintf(cmd, sizeof(cmd), "-D bw_OUTPUT -o %s --jump %s", ifn, costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700554 runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
JP Abgrall0031cea2012-04-17 16:38:23 -0700555
556 snprintf(cmd, sizeof(cmd), "-I bw_OUTPUT %d -o %s --jump %s", ruleInsertPos, ifn, costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700557 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700558 return res;
559}
560
JP Abgrall26e0d492011-06-24 19:21:51 -0700561int BandwidthController::cleanupCostlyIface(const char *ifn, QuotaType quotaType) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700562 char cmd[MAX_CMD_LEN];
563 int res = 0;
564 std::string costString;
565 const char *costCString;
566
JP Abgrall26e0d492011-06-24 19:21:51 -0700567 switch (quotaType) {
568 case QuotaUnique:
JP Abgrall7e51cde2013-07-03 13:33:05 -0700569 costString = "bw_costly_";
JP Abgrall0dad7c22011-06-24 11:58:14 -0700570 costString += ifn;
571 costCString = costString.c_str();
JP Abgrall26e0d492011-06-24 19:21:51 -0700572 break;
573 case QuotaShared:
JP Abgrall7e51cde2013-07-03 13:33:05 -0700574 costCString = "bw_costly_shared";
JP Abgrall26e0d492011-06-24 19:21:51 -0700575 break;
JP Abgrall0031cea2012-04-17 16:38:23 -0700576 default:
577 ALOGE("Unexpected quotatype %d", quotaType);
578 return -1;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700579 }
580
JP Abgrall0031cea2012-04-17 16:38:23 -0700581 snprintf(cmd, sizeof(cmd), "-D bw_INPUT -i %s --jump %s", ifn, costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700582 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
JP Abgrall0031cea2012-04-17 16:38:23 -0700583 snprintf(cmd, sizeof(cmd), "-D bw_OUTPUT -o %s --jump %s", ifn, costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700584 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700585
JP Abgrall7e51cde2013-07-03 13:33:05 -0700586 /* The "-N bw_costly_shared" is created upfront, no need to handle it here. */
JP Abgrall26e0d492011-06-24 19:21:51 -0700587 if (quotaType == QuotaUnique) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700588 snprintf(cmd, sizeof(cmd), "-F %s", costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700589 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
JP Abgralla9f802c2011-06-29 15:46:45 -0700590 snprintf(cmd, sizeof(cmd), "-X %s", costCString);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700591 res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700592 }
593 return res;
594}
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700595
JP Abgrall0dad7c22011-06-24 11:58:14 -0700596int BandwidthController::setInterfaceSharedQuota(const char *iface, int64_t maxBytes) {
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700597 char cmd[MAX_CMD_LEN];
598 char ifn[MAX_IFACENAME_LEN];
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700599 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700600 std::string quotaCmd;
JP Abgrall8a932722011-07-13 19:17:35 -0700601 std::string ifaceName;
602 ;
JP Abgrallbfa74662011-06-29 19:23:04 -0700603 const char *costName = "shared";
JP Abgrall26e0d492011-06-24 19:21:51 -0700604 std::list<std::string>::iterator it;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700605
JP Abgrall8a932722011-07-13 19:17:35 -0700606 if (!maxBytes) {
607 /* Don't talk about -1, deprecate it. */
Steve Block5ea0c052012-01-06 19:18:11 +0000608 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700609 return -1;
610 }
JP Abgrall26e0d492011-06-24 19:21:51 -0700611 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000612 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700613 return -1;
614 }
615 ifaceName = ifn;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700616
617 if (maxBytes == -1) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700618 return removeInterfaceSharedQuota(ifn);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700619 }
620
621 /* Insert ingress quota. */
JP Abgrall0dad7c22011-06-24 11:58:14 -0700622 for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) {
623 if (*it == ifaceName)
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700624 break;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700625 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700626
JP Abgrall0dad7c22011-06-24 11:58:14 -0700627 if (it == sharedQuotaIfaces.end()) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700628 res |= prepCostlyIface(ifn, QuotaShared);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700629 if (sharedQuotaIfaces.empty()) {
JP Abgrall0dad7c22011-06-24 11:58:14 -0700630 quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700631 res |= runIpxtablesCmd(quotaCmd.c_str(), IptJumpReject);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700632 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000633 ALOGE("Failed set quota rule");
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700634 goto fail;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700635 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700636 sharedQuotaBytes = maxBytes;
637 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700638 sharedQuotaIfaces.push_front(ifaceName);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700639
640 }
641
642 if (maxBytes != sharedQuotaBytes) {
JP Abgrall8a932722011-07-13 19:17:35 -0700643 res |= updateQuota(costName, maxBytes);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700644 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000645 ALOGE("Failed update quota for %s", costName);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700646 goto fail;
647 }
648 sharedQuotaBytes = maxBytes;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700649 }
650 return 0;
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700651
652 fail:
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700653 /*
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700654 * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
655 * rules in the kernel to see which ones need cleaning up.
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700656 * For now callers needs to choose if they want to "ndc bandwidth enable"
657 * which resets everything.
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700658 */
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700659 removeInterfaceSharedQuota(ifn);
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700660 return -1;
661}
662
JP Abgrall8a932722011-07-13 19:17:35 -0700663/* It will also cleanup any shared alerts */
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700664int BandwidthController::removeInterfaceSharedQuota(const char *iface) {
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700665 char ifn[MAX_IFACENAME_LEN];
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700666 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700667 std::string ifaceName;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700668 std::list<std::string>::iterator it;
JP Abgrallbfa74662011-06-29 19:23:04 -0700669 const char *costName = "shared";
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700670
JP Abgrall8a932722011-07-13 19:17:35 -0700671 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000672 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700673 return -1;
674 }
JP Abgrall8a932722011-07-13 19:17:35 -0700675 ifaceName = ifn;
JP Abgrall26e0d492011-06-24 19:21:51 -0700676
JP Abgrall0dad7c22011-06-24 11:58:14 -0700677 for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) {
678 if (*it == ifaceName)
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700679 break;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700680 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700681 if (it == sharedQuotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000682 ALOGE("No such iface %s to delete", ifn);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700683 return -1;
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700684 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700685
JP Abgrall26e0d492011-06-24 19:21:51 -0700686 res |= cleanupCostlyIface(ifn, QuotaShared);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700687 sharedQuotaIfaces.erase(it);
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700688
JP Abgrall0dad7c22011-06-24 11:58:14 -0700689 if (sharedQuotaIfaces.empty()) {
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700690 std::string quotaCmd;
JP Abgrallbfa74662011-06-29 19:23:04 -0700691 quotaCmd = makeIptablesQuotaCmd(IptOpDelete, costName, sharedQuotaBytes);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700692 res |= runIpxtablesCmd(quotaCmd.c_str(), IptJumpReject);
JP Abgrall8a932722011-07-13 19:17:35 -0700693 sharedQuotaBytes = 0;
694 if (sharedAlertBytes) {
695 removeSharedAlert();
696 sharedAlertBytes = 0;
697 }
JP Abgrallfa6f46d2011-06-17 23:17:28 -0700698 }
JP Abgrall4a5f5ca2011-06-15 18:37:39 -0700699 return res;
700}
JP Abgrall0dad7c22011-06-24 11:58:14 -0700701
702int BandwidthController::setInterfaceQuota(const char *iface, int64_t maxBytes) {
703 char ifn[MAX_IFACENAME_LEN];
704 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700705 std::string ifaceName;
706 const char *costName;
707 std::list<QuotaInfo>::iterator it;
708 std::string quotaCmd;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700709
JP Abgrall8a932722011-07-13 19:17:35 -0700710 if (!maxBytes) {
711 /* Don't talk about -1, deprecate it. */
Steve Block5ea0c052012-01-06 19:18:11 +0000712 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700713 return -1;
714 }
JP Abgrall0dad7c22011-06-24 11:58:14 -0700715 if (maxBytes == -1) {
JP Abgrall26e0d492011-06-24 19:21:51 -0700716 return removeInterfaceQuota(iface);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700717 }
718
JP Abgrall8a932722011-07-13 19:17:35 -0700719 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000720 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700721 return -1;
722 }
723 ifaceName = ifn;
724 costName = iface;
725
JP Abgrall0dad7c22011-06-24 11:58:14 -0700726 /* Insert ingress quota. */
JP Abgrall0dad7c22011-06-24 11:58:14 -0700727 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
JP Abgrall8a932722011-07-13 19:17:35 -0700728 if (it->ifaceName == ifaceName)
JP Abgrall0dad7c22011-06-24 11:58:14 -0700729 break;
730 }
731
732 if (it == quotaIfaces.end()) {
JP Abgralle4788732013-07-02 20:28:45 -0700733 /* Preparing the iface adds a penalty/happy box check */
JP Abgrall26e0d492011-06-24 19:21:51 -0700734 res |= prepCostlyIface(ifn, QuotaUnique);
JP Abgrallbaeccc42013-06-25 09:44:10 -0700735 /*
JP Abgralle4788732013-07-02 20:28:45 -0700736 * The rejecting quota limit should go after the penalty/happy box checks
JP Abgrallbaeccc42013-06-25 09:44:10 -0700737 * or else a naughty app could just eat up the quota.
738 * So we append here.
739 */
JP Abgrall109899b2013-02-12 19:20:13 -0800740 quotaCmd = makeIptablesQuotaCmd(IptOpAppend, costName, maxBytes);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700741 res |= runIpxtablesCmd(quotaCmd.c_str(), IptJumpReject);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700742 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000743 ALOGE("Failed set quota rule");
JP Abgrall0dad7c22011-06-24 11:58:14 -0700744 goto fail;
745 }
746
JP Abgrall8a932722011-07-13 19:17:35 -0700747 quotaIfaces.push_front(QuotaInfo(ifaceName, maxBytes, 0));
JP Abgrall0dad7c22011-06-24 11:58:14 -0700748
749 } else {
JP Abgrall8a932722011-07-13 19:17:35 -0700750 res |= updateQuota(costName, maxBytes);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700751 if (res) {
Steve Block5ea0c052012-01-06 19:18:11 +0000752 ALOGE("Failed update quota for %s", iface);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700753 goto fail;
754 }
JP Abgrall8a932722011-07-13 19:17:35 -0700755 it->quota = maxBytes;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700756 }
757 return 0;
758
759 fail:
760 /*
761 * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
762 * rules in the kernel to see which ones need cleaning up.
763 * For now callers needs to choose if they want to "ndc bandwidth enable"
764 * which resets everything.
765 */
766 removeInterfaceSharedQuota(ifn);
767 return -1;
768}
769
JP Abgrall8a932722011-07-13 19:17:35 -0700770int BandwidthController::getInterfaceSharedQuota(int64_t *bytes) {
771 return getInterfaceQuota("shared", bytes);
772}
773
774int BandwidthController::getInterfaceQuota(const char *costName, int64_t *bytes) {
775 FILE *fp;
776 char *fname;
777 int scanRes;
778
779 asprintf(&fname, "/proc/net/xt_quota/%s", costName);
780 fp = fopen(fname, "r");
781 free(fname);
782 if (!fp) {
Steve Block5ea0c052012-01-06 19:18:11 +0000783 ALOGE("Reading quota %s failed (%s)", costName, strerror(errno));
JP Abgrall8a932722011-07-13 19:17:35 -0700784 return -1;
785 }
Matthew Leach2a54d962013-01-14 15:07:12 +0000786 scanRes = fscanf(fp, "%"PRId64, bytes);
787 ALOGV("Read quota res=%d bytes=%"PRId64, scanRes, *bytes);
JP Abgrall8a932722011-07-13 19:17:35 -0700788 fclose(fp);
789 return scanRes == 1 ? 0 : -1;
790}
791
JP Abgrall0dad7c22011-06-24 11:58:14 -0700792int BandwidthController::removeInterfaceQuota(const char *iface) {
793
794 char ifn[MAX_IFACENAME_LEN];
795 int res = 0;
JP Abgrall26e0d492011-06-24 19:21:51 -0700796 std::string ifaceName;
797 const char *costName;
JP Abgrall0dad7c22011-06-24 11:58:14 -0700798 std::list<QuotaInfo>::iterator it;
JP Abgrall26e0d492011-06-24 19:21:51 -0700799
JP Abgrall8a932722011-07-13 19:17:35 -0700800 if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
Steve Block5ea0c052012-01-06 19:18:11 +0000801 ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
JP Abgrall26e0d492011-06-24 19:21:51 -0700802 return -1;
803 }
804 ifaceName = ifn;
805 costName = iface;
806
JP Abgrall0dad7c22011-06-24 11:58:14 -0700807 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
JP Abgrall8a932722011-07-13 19:17:35 -0700808 if (it->ifaceName == ifaceName)
JP Abgrall0dad7c22011-06-24 11:58:14 -0700809 break;
810 }
811
812 if (it == quotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +0000813 ALOGE("No such iface %s to delete", ifn);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700814 return -1;
815 }
816
817 /* This also removes the quota command of CostlyIface chain. */
JP Abgrall26e0d492011-06-24 19:21:51 -0700818 res |= cleanupCostlyIface(ifn, QuotaUnique);
JP Abgrall0dad7c22011-06-24 11:58:14 -0700819
820 quotaIfaces.erase(it);
821
822 return res;
823}
JP Abgrall8a932722011-07-13 19:17:35 -0700824
825int BandwidthController::updateQuota(const char *quotaName, int64_t bytes) {
826 FILE *fp;
827 char *fname;
828
829 asprintf(&fname, "/proc/net/xt_quota/%s", quotaName);
830 fp = fopen(fname, "w");
831 free(fname);
832 if (!fp) {
Steve Block5ea0c052012-01-06 19:18:11 +0000833 ALOGE("Updating quota %s failed (%s)", quotaName, strerror(errno));
JP Abgrall8a932722011-07-13 19:17:35 -0700834 return -1;
835 }
Matthew Leach2a54d962013-01-14 15:07:12 +0000836 fprintf(fp, "%"PRId64"\n", bytes);
JP Abgrall8a932722011-07-13 19:17:35 -0700837 fclose(fp);
838 return 0;
839}
840
841int BandwidthController::runIptablesAlertCmd(IptOp op, const char *alertName, int64_t bytes) {
842 int res = 0;
843 const char *opFlag;
844 char *alertQuotaCmd;
845
846 switch (op) {
847 case IptOpInsert:
848 opFlag = "-I";
849 break;
JP Abgrall109899b2013-02-12 19:20:13 -0800850 case IptOpAppend:
851 opFlag = "-A";
852 break;
JP Abgrall8a932722011-07-13 19:17:35 -0700853 case IptOpReplace:
854 opFlag = "-R";
855 break;
856 default:
857 case IptOpDelete:
858 opFlag = "-D";
859 break;
860 }
861
JP Abgrall92009c82013-02-06 18:01:24 -0800862 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_INPUT",
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800863 bytes, alertName);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700864 res |= runIpxtablesCmd(alertQuotaCmd, IptJumpNoAdd);
JP Abgrall8a932722011-07-13 19:17:35 -0700865 free(alertQuotaCmd);
JP Abgrall92009c82013-02-06 18:01:24 -0800866 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_OUTPUT",
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800867 bytes, alertName);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700868 res |= runIpxtablesCmd(alertQuotaCmd, IptJumpNoAdd);
JP Abgrall8a932722011-07-13 19:17:35 -0700869 free(alertQuotaCmd);
870 return res;
871}
872
JP Abgrallc6c67342011-10-07 16:28:54 -0700873int BandwidthController::runIptablesAlertFwdCmd(IptOp op, const char *alertName, int64_t bytes) {
874 int res = 0;
875 const char *opFlag;
JP Abgrall8a932722011-07-13 19:17:35 -0700876 char *alertQuotaCmd;
JP Abgrallc6c67342011-10-07 16:28:54 -0700877
878 switch (op) {
879 case IptOpInsert:
880 opFlag = "-I";
881 break;
JP Abgrall109899b2013-02-12 19:20:13 -0800882 case IptOpAppend:
883 opFlag = "-A";
884 break;
JP Abgrallc6c67342011-10-07 16:28:54 -0700885 case IptOpReplace:
886 opFlag = "-R";
887 break;
888 default:
889 case IptOpDelete:
890 opFlag = "-D";
891 break;
892 }
893
JP Abgrall92009c82013-02-06 18:01:24 -0800894 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_FORWARD",
Nick Kralevichc2b26cb2012-02-23 13:04:26 -0800895 bytes, alertName);
JP Abgralla9ba4cb2013-07-02 19:08:48 -0700896 res = runIpxtablesCmd(alertQuotaCmd, IptJumpNoAdd);
JP Abgrallc6c67342011-10-07 16:28:54 -0700897 free(alertQuotaCmd);
898 return res;
899}
900
901int BandwidthController::setGlobalAlert(int64_t bytes) {
902 const char *alertName = ALERT_GLOBAL_NAME;
JP Abgrall8a932722011-07-13 19:17:35 -0700903 int res = 0;
904
905 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000906 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700907 return -1;
908 }
909 if (globalAlertBytes) {
910 res = updateQuota(alertName, bytes);
911 } else {
912 res = runIptablesAlertCmd(IptOpInsert, alertName, bytes);
JP Abgrallc6c67342011-10-07 16:28:54 -0700913 if (globalAlertTetherCount) {
Steve Block3fb42e02011-10-20 11:55:56 +0100914 ALOGV("setGlobalAlert for %d tether", globalAlertTetherCount);
JP Abgrallc6c67342011-10-07 16:28:54 -0700915 res |= runIptablesAlertFwdCmd(IptOpInsert, alertName, bytes);
916 }
JP Abgrall8a932722011-07-13 19:17:35 -0700917 }
918 globalAlertBytes = bytes;
919 return res;
920}
921
JP Abgrallc6c67342011-10-07 16:28:54 -0700922int BandwidthController::setGlobalAlertInForwardChain(void) {
923 const char *alertName = ALERT_GLOBAL_NAME;
924 int res = 0;
JP Abgrall8a932722011-07-13 19:17:35 -0700925
JP Abgrallc6c67342011-10-07 16:28:54 -0700926 globalAlertTetherCount++;
Steve Block3fb42e02011-10-20 11:55:56 +0100927 ALOGV("setGlobalAlertInForwardChain(): %d tether", globalAlertTetherCount);
JP Abgrallc6c67342011-10-07 16:28:54 -0700928
929 /*
930 * If there is no globalAlert active we are done.
931 * If there is an active globalAlert but this is not the 1st
932 * tether, we are also done.
933 */
934 if (!globalAlertBytes || globalAlertTetherCount != 1) {
935 return 0;
936 }
937
938 /* We only add the rule if this was the 1st tether added. */
939 res = runIptablesAlertFwdCmd(IptOpInsert, alertName, globalAlertBytes);
940 return res;
941}
942
943int BandwidthController::removeGlobalAlert(void) {
944
945 const char *alertName = ALERT_GLOBAL_NAME;
JP Abgrall8a932722011-07-13 19:17:35 -0700946 int res = 0;
947
948 if (!globalAlertBytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000949 ALOGE("No prior alert set");
JP Abgrall8a932722011-07-13 19:17:35 -0700950 return -1;
951 }
952 res = runIptablesAlertCmd(IptOpDelete, alertName, globalAlertBytes);
JP Abgrallc6c67342011-10-07 16:28:54 -0700953 if (globalAlertTetherCount) {
954 res |= runIptablesAlertFwdCmd(IptOpDelete, alertName, globalAlertBytes);
955 }
JP Abgrall8a932722011-07-13 19:17:35 -0700956 globalAlertBytes = 0;
957 return res;
958}
959
JP Abgrallc6c67342011-10-07 16:28:54 -0700960int BandwidthController::removeGlobalAlertInForwardChain(void) {
961 int res = 0;
962 const char *alertName = ALERT_GLOBAL_NAME;
963
964 if (!globalAlertTetherCount) {
Steve Block5ea0c052012-01-06 19:18:11 +0000965 ALOGE("No prior alert set");
JP Abgrallc6c67342011-10-07 16:28:54 -0700966 return -1;
967 }
968
969 globalAlertTetherCount--;
970 /*
971 * If there is no globalAlert active we are done.
972 * If there is an active globalAlert but there are more
973 * tethers, we are also done.
974 */
975 if (!globalAlertBytes || globalAlertTetherCount >= 1) {
976 return 0;
977 }
978
979 /* We only detete the rule if this was the last tether removed. */
980 res = runIptablesAlertFwdCmd(IptOpDelete, alertName, globalAlertBytes);
981 return res;
982}
983
JP Abgrall8a932722011-07-13 19:17:35 -0700984int BandwidthController::setSharedAlert(int64_t bytes) {
985 if (!sharedQuotaBytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000986 ALOGE("Need to have a prior shared quota set to set an alert");
JP Abgrall8a932722011-07-13 19:17:35 -0700987 return -1;
988 }
989 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +0000990 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -0700991 return -1;
992 }
993 return setCostlyAlert("shared", bytes, &sharedAlertBytes);
994}
995
996int BandwidthController::removeSharedAlert(void) {
997 return removeCostlyAlert("shared", &sharedAlertBytes);
998}
999
1000int BandwidthController::setInterfaceAlert(const char *iface, int64_t bytes) {
1001 std::list<QuotaInfo>::iterator it;
1002
1003 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +00001004 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -07001005 return -1;
1006 }
1007 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
1008 if (it->ifaceName == iface)
1009 break;
1010 }
1011
1012 if (it == quotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +00001013 ALOGE("Need to have a prior interface quota set to set an alert");
JP Abgrall8a932722011-07-13 19:17:35 -07001014 return -1;
1015 }
1016
1017 return setCostlyAlert(iface, bytes, &it->alert);
1018}
1019
1020int BandwidthController::removeInterfaceAlert(const char *iface) {
1021 std::list<QuotaInfo>::iterator it;
1022
1023 for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
1024 if (it->ifaceName == iface)
1025 break;
1026 }
1027
1028 if (it == quotaIfaces.end()) {
Steve Block5ea0c052012-01-06 19:18:11 +00001029 ALOGE("No prior alert set for interface %s", iface);
JP Abgrall8a932722011-07-13 19:17:35 -07001030 return -1;
1031 }
1032
1033 return removeCostlyAlert(iface, &it->alert);
1034}
1035
1036int BandwidthController::setCostlyAlert(const char *costName, int64_t bytes, int64_t *alertBytes) {
1037 char *alertQuotaCmd;
JP Abgrall109899b2013-02-12 19:20:13 -08001038 char *chainName;
JP Abgrall8a932722011-07-13 19:17:35 -07001039 int res = 0;
1040 char *alertName;
1041
1042 if (!bytes) {
Steve Block5ea0c052012-01-06 19:18:11 +00001043 ALOGE("Invalid bytes value. 1..max_int64.");
JP Abgrall8a932722011-07-13 19:17:35 -07001044 return -1;
1045 }
1046 asprintf(&alertName, "%sAlert", costName);
1047 if (*alertBytes) {
1048 res = updateQuota(alertName, *alertBytes);
1049 } else {
JP Abgrall7e51cde2013-07-03 13:33:05 -07001050 asprintf(&chainName, "bw_costly_%s", costName);
JP Abgrall109899b2013-02-12 19:20:13 -08001051 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "-A", chainName, bytes, alertName);
JP Abgralla9ba4cb2013-07-02 19:08:48 -07001052 res |= runIpxtablesCmd(alertQuotaCmd, IptJumpNoAdd);
JP Abgrall8a932722011-07-13 19:17:35 -07001053 free(alertQuotaCmd);
JP Abgrall109899b2013-02-12 19:20:13 -08001054 free(chainName);
JP Abgrall8a932722011-07-13 19:17:35 -07001055 }
1056 *alertBytes = bytes;
1057 free(alertName);
1058 return res;
1059}
1060
1061int BandwidthController::removeCostlyAlert(const char *costName, int64_t *alertBytes) {
1062 char *alertQuotaCmd;
1063 char *chainName;
1064 char *alertName;
1065 int res = 0;
1066
1067 asprintf(&alertName, "%sAlert", costName);
1068 if (!*alertBytes) {
Steve Block5ea0c052012-01-06 19:18:11 +00001069 ALOGE("No prior alert set for %s alert", costName);
JP Abgrall8a932722011-07-13 19:17:35 -07001070 return -1;
1071 }
1072
JP Abgrall7e51cde2013-07-03 13:33:05 -07001073 asprintf(&chainName, "bw_costly_%s", costName);
JP Abgrall92009c82013-02-06 18:01:24 -08001074 asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "-D", chainName, *alertBytes, alertName);
JP Abgralla9ba4cb2013-07-02 19:08:48 -07001075 res |= runIpxtablesCmd(alertQuotaCmd, IptJumpNoAdd);
JP Abgrall8a932722011-07-13 19:17:35 -07001076 free(alertQuotaCmd);
1077 free(chainName);
1078
1079 *alertBytes = 0;
1080 free(alertName);
1081 return res;
1082}
JP Abgralldb7da582011-09-18 12:57:32 -07001083
1084/*
1085 * Parse the ptks and bytes out of:
JP Abgrallbaeccc42013-06-25 09:44:10 -07001086 * Chain natctrl_tether_counters (4 references)
1087 * pkts bytes target prot opt in out source destination
1088 * 26 2373 RETURN all -- wlan0 rmnet0 0.0.0.0/0 0.0.0.0/0 counter wlan0_rmnet0: 0 bytes
1089 * 27 2002 RETURN all -- rmnet0 wlan0 0.0.0.0/0 0.0.0.0/0 counter rmnet0_wlan0: 0 bytes
1090 * 1040 107471 RETURN all -- bt-pan rmnet0 0.0.0.0/0 0.0.0.0/0 counter bt-pan_rmnet0: 0 bytes
1091 * 1450 1708806 RETURN all -- rmnet0 bt-pan 0.0.0.0/0 0.0.0.0/0 counter rmnet0_bt-pan: 0 bytes
JP Abgralldb7da582011-09-18 12:57:32 -07001092 */
JP Abgrallbaeccc42013-06-25 09:44:10 -07001093int BandwidthController::parseForwardChainStats(SocketClient *cli, const TetherStats filter,
1094 FILE *fp, std::string &extraProcessingInfo) {
JP Abgralldb7da582011-09-18 12:57:32 -07001095 int res;
1096 char lineBuffer[MAX_IPT_OUTPUT_LINE_LEN];
1097 char iface0[MAX_IPT_OUTPUT_LINE_LEN];
1098 char iface1[MAX_IPT_OUTPUT_LINE_LEN];
1099 char rest[MAX_IPT_OUTPUT_LINE_LEN];
1100
JP Abgrallbaeccc42013-06-25 09:44:10 -07001101 TetherStats stats;
JP Abgralldb7da582011-09-18 12:57:32 -07001102 char *buffPtr;
1103 int64_t packets, bytes;
JP Abgrallbaeccc42013-06-25 09:44:10 -07001104
1105 bool filterPair = filter.intIface[0] && filter.extIface[0];
1106
1107 char *filterMsg = filter.getStatsLine();
1108 ALOGV("filter: %s", filterMsg);
1109 free(filterMsg);
1110
1111 stats = filter;
JP Abgralldb7da582011-09-18 12:57:32 -07001112
1113 while (NULL != (buffPtr = fgets(lineBuffer, MAX_IPT_OUTPUT_LINE_LEN, fp))) {
1114 /* Clean up, so a failed parse can still print info */
1115 iface0[0] = iface1[0] = rest[0] = packets = bytes = 0;
Matthew Leach2a54d962013-01-14 15:07:12 +00001116 res = sscanf(buffPtr, "%"PRId64" %"PRId64" RETURN all -- %s %s 0.%s",
JP Abgralldb7da582011-09-18 12:57:32 -07001117 &packets, &bytes, iface0, iface1, rest);
Matthew Leach2a54d962013-01-14 15:07:12 +00001118 ALOGV("parse res=%d iface0=<%s> iface1=<%s> pkts=%"PRId64" bytes=%"PRId64" rest=<%s> orig line=<%s>", res,
JP Abgralldb7da582011-09-18 12:57:32 -07001119 iface0, iface1, packets, bytes, rest, buffPtr);
JP Abgralla2a64f02011-11-11 20:36:16 -08001120 extraProcessingInfo += buffPtr;
1121
JP Abgralldb7da582011-09-18 12:57:32 -07001122 if (res != 5) {
1123 continue;
1124 }
JP Abgrallbaeccc42013-06-25 09:44:10 -07001125 /*
1126 * The following assumes that the 1st rule has in:extIface out:intIface,
1127 * which is what NatController sets up.
1128 * If not filtering, the 1st match rx, and sets up the pair for the tx side.
1129 */
1130 if (filter.intIface[0] && filter.extIface[0]) {
1131 if (filter.intIface == iface0 && filter.extIface == iface1) {
Matthew Leach2a54d962013-01-14 15:07:12 +00001132 ALOGV("2Filter RX iface_in=%s iface_out=%s rx_bytes=%"PRId64" rx_packets=%"PRId64" ", iface0, iface1, bytes, packets);
JP Abgrallbaeccc42013-06-25 09:44:10 -07001133 stats.rxPackets = packets;
1134 stats.rxBytes = bytes;
1135 } else if (filter.intIface == iface1 && filter.extIface == iface0) {
Matthew Leach2a54d962013-01-14 15:07:12 +00001136 ALOGV("2Filter TX iface_in=%s iface_out=%s rx_bytes=%"PRId64" rx_packets=%"PRId64" ", iface0, iface1, bytes, packets);
JP Abgrallbaeccc42013-06-25 09:44:10 -07001137 stats.txPackets = packets;
1138 stats.txBytes = bytes;
1139 }
1140 } else if (filter.intIface[0] || filter.extIface[0]) {
1141 if (filter.intIface == iface0 || filter.extIface == iface1) {
Matthew Leach2a54d962013-01-14 15:07:12 +00001142 ALOGV("1Filter RX iface_in=%s iface_out=%s rx_bytes=%"PRId64" rx_packets=%"PRId64" ", iface0, iface1, bytes, packets);
JP Abgrallbaeccc42013-06-25 09:44:10 -07001143 stats.intIface = iface0;
1144 stats.extIface = iface1;
1145 stats.rxPackets = packets;
1146 stats.rxBytes = bytes;
1147 } else if (filter.intIface == iface1 || filter.extIface == iface0) {
Matthew Leach2a54d962013-01-14 15:07:12 +00001148 ALOGV("1Filter TX iface_in=%s iface_out=%s rx_bytes=%"PRId64" rx_packets=%"PRId64" ", iface0, iface1, bytes, packets);
JP Abgrallbaeccc42013-06-25 09:44:10 -07001149 stats.intIface = iface1;
1150 stats.extIface = iface0;
1151 stats.txPackets = packets;
1152 stats.txBytes = bytes;
1153 }
1154 } else /* if (!filter.intFace[0] && !filter.extIface[0]) */ {
1155 if (!stats.intIface[0]) {
Matthew Leach2a54d962013-01-14 15:07:12 +00001156 ALOGV("0Filter RX iface_in=%s iface_out=%s rx_bytes=%"PRId64" rx_packets=%"PRId64" ", iface0, iface1, bytes, packets);
JP Abgrallbaeccc42013-06-25 09:44:10 -07001157 stats.intIface = iface0;
1158 stats.extIface = iface1;
1159 stats.rxPackets = packets;
1160 stats.rxBytes = bytes;
1161 } else if (stats.intIface == iface1 && stats.extIface == iface0) {
Matthew Leach2a54d962013-01-14 15:07:12 +00001162 ALOGV("0Filter TX iface_in=%s iface_out=%s rx_bytes=%"PRId64" rx_packets=%"PRId64" ", iface0, iface1, bytes, packets);
JP Abgrallbaeccc42013-06-25 09:44:10 -07001163 stats.txPackets = packets;
1164 stats.txBytes = bytes;
1165 }
1166 }
1167 if (stats.rxBytes != -1 && stats.txBytes != -1) {
Matthew Leach2a54d962013-01-14 15:07:12 +00001168 ALOGV("rx_bytes=%"PRId64" tx_bytes=%"PRId64" filterPair=%d", stats.rxBytes, stats.txBytes, filterPair);
JP Abgrallbaeccc42013-06-25 09:44:10 -07001169 /* Send out stats, and prep for the next if needed. */
1170 char *msg = stats.getStatsLine();
1171 if (filterPair) {
1172 cli->sendMsg(ResponseCode::TetheringStatsResult, msg, false);
1173 return 0;
1174 } else {
1175 cli->sendMsg(ResponseCode::TetheringStatsListResult, msg, false);
1176 stats = filter;
1177 }
1178 free(msg);
JP Abgralldb7da582011-09-18 12:57:32 -07001179 }
1180 }
Jeff Sharkey991693e2013-09-10 20:53:58 -07001181 /* Successful if the last stats entry wasn't partial. */
1182 if ((stats.rxBytes == -1) == (stats.txBytes == -1)) {
JP Abgrallbaeccc42013-06-25 09:44:10 -07001183 cli->sendMsg(ResponseCode::CommandOkay, "Tethering stats list completed", false);
1184 return 0;
1185 }
1186 return -1;
JP Abgralldb7da582011-09-18 12:57:32 -07001187}
1188
JP Abgrallbaeccc42013-06-25 09:44:10 -07001189char *BandwidthController::TetherStats::getStatsLine(void) const {
JP Abgralldb7da582011-09-18 12:57:32 -07001190 char *msg;
Matthew Leach2a54d962013-01-14 15:07:12 +00001191 asprintf(&msg, "%s %s %"PRId64" %"PRId64" %"PRId64" %"PRId64, intIface.c_str(), extIface.c_str(),
JP Abgralldb7da582011-09-18 12:57:32 -07001192 rxBytes, rxPackets, txBytes, txPackets);
1193 return msg;
1194}
1195
JP Abgrallbaeccc42013-06-25 09:44:10 -07001196int BandwidthController::getTetherStats(SocketClient *cli, TetherStats &stats, std::string &extraProcessingInfo) {
JP Abgralldb7da582011-09-18 12:57:32 -07001197 int res;
1198 std::string fullCmd;
1199 FILE *iptOutput;
1200 const char *cmd;
1201
JP Abgralldb7da582011-09-18 12:57:32 -07001202 /*
1203 * Why not use some kind of lib to talk to iptables?
1204 * Because the only libs are libiptc and libip6tc in iptables, and they are
1205 * not easy to use. They require the known iptables match modules to be
1206 * preloaded/linked, and require apparently a lot of wrapper code to get
1207 * the wanted info.
1208 */
1209 fullCmd = IPTABLES_PATH;
JP Abgrallbaeccc42013-06-25 09:44:10 -07001210 fullCmd += " -nvx -L ";
1211 fullCmd += NatController::LOCAL_TETHER_COUNTERS_CHAIN;
JP Abgralldb7da582011-09-18 12:57:32 -07001212 iptOutput = popen(fullCmd.c_str(), "r");
1213 if (!iptOutput) {
Steve Block5ea0c052012-01-06 19:18:11 +00001214 ALOGE("Failed to run %s err=%s", fullCmd.c_str(), strerror(errno));
JP Abgralla2a64f02011-11-11 20:36:16 -08001215 extraProcessingInfo += "Failed to run iptables.";
JP Abgralldb7da582011-09-18 12:57:32 -07001216 return -1;
1217 }
JP Abgrallbaeccc42013-06-25 09:44:10 -07001218 res = parseForwardChainStats(cli, stats, iptOutput, extraProcessingInfo);
JP Abgralldb7da582011-09-18 12:57:32 -07001219 pclose(iptOutput);
1220
1221 /* Currently NatController doesn't do ipv6 tethering, so we are done. */
1222 return res;
1223}
JP Abgrall0e540ec2013-08-26 15:13:10 -07001224
1225void BandwidthController::flushExistingCostlyTables(bool doClean) {
1226 int res;
1227 std::string fullCmd;
1228 FILE *iptOutput;
1229 const char *cmd;
1230
1231 /* Only lookup ip4 table names as ip6 will have the same tables ... */
1232 fullCmd = IPTABLES_PATH;
1233 fullCmd += " -S";
1234 iptOutput = popen(fullCmd.c_str(), "r");
1235 if (!iptOutput) {
1236 ALOGE("Failed to run %s err=%s", fullCmd.c_str(), strerror(errno));
1237 return;
1238 }
1239 /* ... then flush/clean both ip4 and ip6 iptables. */
1240 parseAndFlushCostlyTables(iptOutput, doClean);
1241 pclose(iptOutput);
1242}
1243
1244void BandwidthController::parseAndFlushCostlyTables(FILE *fp, bool doRemove) {
1245 int res;
1246 char lineBuffer[MAX_IPT_OUTPUT_LINE_LEN];
1247 char costlyIfaceName[MAX_IPT_OUTPUT_LINE_LEN];
1248 char cmd[MAX_CMD_LEN];
1249 char *buffPtr;
1250
1251 while (NULL != (buffPtr = fgets(lineBuffer, MAX_IPT_OUTPUT_LINE_LEN, fp))) {
1252 costlyIfaceName[0] = '\0'; /* So that debugging output always works */
1253 res = sscanf(buffPtr, "-N bw_costly_%s", costlyIfaceName);
1254 ALOGV("parse res=%d costly=<%s> orig line=<%s>", res,
1255 costlyIfaceName, buffPtr);
1256 if (res != 1) {
1257 continue;
1258 }
1259 /* Exclusions: "shared" is not an ifacename */
1260 if (!strcmp(costlyIfaceName, "shared")) {
1261 continue;
1262 }
1263
1264 snprintf(cmd, sizeof(cmd), "-F bw_costly_%s", costlyIfaceName);
1265 runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
1266 if (doRemove) {
1267 snprintf(cmd, sizeof(cmd), "-X bw_costly_%s", costlyIfaceName);
1268 runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
1269 }
1270 }
1271}