OSDN Git Service

ae78d95e84967bcb6edda0361242ef6b7a9ebbcb
[android-x86/system-netd.git] / server / BandwidthController.cpp
1 /*
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
17 // #define LOG_NDEBUG 0
18
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
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <ctype.h>
31
32 #define __STDC_FORMAT_MACROS 1
33 #include <inttypes.h>
34
35 #include <sys/socket.h>
36 #include <sys/stat.h>
37 #include <sys/types.h>
38 #include <sys/wait.h>
39
40 #include <linux/netlink.h>
41 #include <linux/rtnetlink.h>
42 #include <linux/pkt_sched.h>
43
44 #define LOG_TAG "BandwidthController"
45 #include <cutils/log.h>
46 #include <cutils/properties.h>
47 #include <logwrap/logwrap.h>
48
49 #include "NetdConstants.h"
50 #include "BandwidthController.h"
51 #include "NatController.h"  /* For LOCAL_TETHER_COUNTERS_CHAIN */
52 #include "ResponseCode.h"
53
54 /* Alphabetical */
55 #define ALERT_IPT_TEMPLATE "%s %s -m quota2 ! --quota %" PRId64" --name %s"
56 const char BandwidthController::ALERT_GLOBAL_NAME[] = "globalAlert";
57 const char* BandwidthController::LOCAL_INPUT = "bw_INPUT";
58 const char* BandwidthController::LOCAL_FORWARD = "bw_FORWARD";
59 const char* BandwidthController::LOCAL_OUTPUT = "bw_OUTPUT";
60 const char* BandwidthController::LOCAL_RAW_PREROUTING = "bw_raw_PREROUTING";
61 const char* BandwidthController::LOCAL_MANGLE_POSTROUTING = "bw_mangle_POSTROUTING";
62 const int  BandwidthController::MAX_CMD_ARGS = 32;
63 const int  BandwidthController::MAX_CMD_LEN = 1024;
64 const int  BandwidthController::MAX_IFACENAME_LEN = 64;
65 const int  BandwidthController::MAX_IPT_OUTPUT_LINE_LEN = 256;
66
67 /**
68  * Some comments about the rules:
69  *  * Ordering
70  *    - when an interface is marked as costly it should be INSERTED into the INPUT/OUTPUT chains.
71  *      E.g. "-I bw_INPUT -i rmnet0 --jump costly"
72  *    - quota'd rules in the costly chain should be before bw_penalty_box lookups.
73  *    - bw_happy_box rejects everything by default.
74  *    - the qtaguid counting is done at the end of the bw_INPUT/bw_OUTPUT user chains.
75  *
76  * * global quota vs per interface quota
77  *   - global quota for all costly interfaces uses a single costly chain:
78  *    . initial rules
79  *      iptables -N bw_costly_shared
80  *      iptables -I bw_INPUT -i iface0 --jump bw_costly_shared
81  *      iptables -I bw_OUTPUT -o iface0 --jump bw_costly_shared
82  *      iptables -I bw_costly_shared -m quota \! --quota 500000 \
83  *          --jump REJECT --reject-with icmp-net-prohibited
84  *      iptables -A bw_costly_shared --jump bw_penalty_box
85  *      If the happy box is enabled,
86  *        iptables -A bw_penalty_box --jump bw_happy_box
87  *
88  *    . adding a new iface to this, E.g.:
89  *      iptables -I bw_INPUT -i iface1 --jump bw_costly_shared
90  *      iptables -I bw_OUTPUT -o iface1 --jump bw_costly_shared
91  *
92  *   - quota per interface. This is achieve by having "costly" chains per quota.
93  *     E.g. adding a new costly interface iface0 with its own quota:
94  *      iptables -N bw_costly_iface0
95  *      iptables -I bw_INPUT -i iface0 --jump bw_costly_iface0
96  *      iptables -I bw_OUTPUT -o iface0 --jump bw_costly_iface0
97  *      iptables -A bw_costly_iface0 -m quota \! --quota 500000 \
98  *          --jump REJECT --reject-with icmp-port-unreachable
99  *      iptables -A bw_costly_iface0 --jump bw_penalty_box
100  *
101  * * bw_penalty_box handling:
102  *  - only one bw_penalty_box for all interfaces
103  *   E.g  Adding an app, it has to preserve the appened bw_happy_box, so "-I":
104  *    iptables -I bw_penalty_box -m owner --uid-owner app_3 \
105  *        --jump REJECT --reject-with icmp-port-unreachable
106  *
107  * * bw_happy_box handling:
108  *  - The bw_happy_box goes at the end of the penalty box.
109  *   E.g  Adding a happy app,
110  *    iptables -I bw_happy_box -m owner --uid-owner app_3 \
111  *        --jump RETURN
112  */
113 const char *BandwidthController::IPT_FLUSH_COMMANDS[] = {
114     /*
115      * Cleanup rules.
116      * Should normally include bw_costly_<iface>, but we rely on the way they are setup
117      * to allow coexistance.
118      */
119     "-F bw_INPUT",
120     "-F bw_OUTPUT",
121     "-F bw_FORWARD",
122     "-F bw_happy_box",
123     "-F bw_penalty_box",
124     "-F bw_costly_shared",
125
126     "-t raw -F bw_raw_PREROUTING",
127     "-t mangle -F bw_mangle_POSTROUTING",
128 };
129
130 /* The cleanup commands assume flushing has been done. */
131 const char *BandwidthController::IPT_CLEANUP_COMMANDS[] = {
132     "-X bw_happy_box",
133     "-X bw_penalty_box",
134     "-X bw_costly_shared",
135 };
136
137 const char *BandwidthController::IPT_SETUP_COMMANDS[] = {
138     "-N bw_happy_box",
139     "-N bw_penalty_box",
140     "-N bw_costly_shared",
141 };
142
143 const char *BandwidthController::IPT_BASIC_ACCOUNTING_COMMANDS[] = {
144     "-A bw_INPUT -m owner --socket-exists", /* This is a tracking rule. */
145
146     "-A bw_OUTPUT -m owner --socket-exists", /* This is a tracking rule. */
147
148     "-A bw_costly_shared --jump bw_penalty_box",
149
150     "-t raw -A bw_raw_PREROUTING -m owner --socket-exists", /* This is a tracking rule. */
151     "-t mangle -A bw_mangle_POSTROUTING -m owner --socket-exists", /* This is a tracking rule. */
152 };
153
154 BandwidthController::BandwidthController(void) {
155 }
156
157 int BandwidthController::runIpxtablesCmd(const char *cmd, IptJumpOp jumpHandling,
158                                          IptFailureLog failureHandling) {
159     int res = 0;
160
161     ALOGV("runIpxtablesCmd(cmd=%s)", cmd);
162     res |= runIptablesCmd(cmd, jumpHandling, IptIpV4, failureHandling);
163     res |= runIptablesCmd(cmd, jumpHandling, IptIpV6, failureHandling);
164     return res;
165 }
166
167 int BandwidthController::StrncpyAndCheck(char *buffer, const char *src, size_t buffSize) {
168
169     memset(buffer, '\0', buffSize);  // strncpy() is not filling leftover with '\0'
170     strncpy(buffer, src, buffSize);
171     return buffer[buffSize - 1];
172 }
173
174 int BandwidthController::runIptablesCmd(const char *cmd, IptJumpOp jumpHandling,
175                                         IptIpVer iptVer, IptFailureLog failureHandling) {
176     char buffer[MAX_CMD_LEN];
177     const char *argv[MAX_CMD_ARGS];
178     int argc = 0;
179     char *next = buffer;
180     char *tmp;
181     int res;
182     int status = 0;
183
184     std::string fullCmd = cmd;
185
186     switch (jumpHandling) {
187     case IptJumpReject:
188         /*
189          * Must be carefull what one rejects with, as uper layer protocols will just
190          * keep on hammering the device until the number of retries are done.
191          * For port-unreachable (default), TCP should consider as an abort (RFC1122).
192          */
193         fullCmd += " --jump REJECT";
194         break;
195     case IptJumpReturn:
196         fullCmd += " --jump RETURN";
197         break;
198     case IptJumpNoAdd:
199         break;
200     }
201
202     fullCmd.insert(0, " -w ");
203     fullCmd.insert(0, iptVer == IptIpV4 ? IPTABLES_PATH : IP6TABLES_PATH);
204
205     if (StrncpyAndCheck(buffer, fullCmd.c_str(), sizeof(buffer))) {
206         ALOGE("iptables command too long");
207         return -1;
208     }
209
210     argc = 0;
211     while ((tmp = strsep(&next, " "))) {
212         argv[argc++] = tmp;
213         if (argc >= MAX_CMD_ARGS) {
214             ALOGE("iptables argument overflow");
215             return -1;
216         }
217     }
218
219     argv[argc] = NULL;
220     res = android_fork_execvp(argc, (char **)argv, &status, false,
221             failureHandling == IptFailShow);
222     res = res || !WIFEXITED(status) || WEXITSTATUS(status);
223     if (res && failureHandling == IptFailShow) {
224       ALOGE("runIptablesCmd(): res=%d status=%d failed %s", res, status,
225             fullCmd.c_str());
226     }
227     return res;
228 }
229
230 void BandwidthController::flushCleanTables(bool doClean) {
231     /* Flush and remove the bw_costly_<iface> tables */
232     flushExistingCostlyTables(doClean);
233
234     /* Some of the initialCommands are allowed to fail */
235     runCommands(sizeof(IPT_FLUSH_COMMANDS) / sizeof(char*),
236             IPT_FLUSH_COMMANDS, RunCmdFailureOk);
237
238     if (doClean) {
239         runCommands(sizeof(IPT_CLEANUP_COMMANDS) / sizeof(char*),
240                 IPT_CLEANUP_COMMANDS, RunCmdFailureOk);
241     }
242 }
243
244 int BandwidthController::setupIptablesHooks(void) {
245
246     /* flush+clean is allowed to fail */
247     flushCleanTables(true);
248     runCommands(sizeof(IPT_SETUP_COMMANDS) / sizeof(char*),
249             IPT_SETUP_COMMANDS, RunCmdFailureBad);
250
251     return 0;
252 }
253
254 int BandwidthController::enableBandwidthControl(bool force) {
255     int res;
256     char value[PROPERTY_VALUE_MAX];
257
258     if (!force) {
259             property_get("persist.bandwidth.enable", value, "1");
260             if (!strcmp(value, "0"))
261                     return 0;
262     }
263
264     /* Let's pretend we started from scratch ... */
265     sharedQuotaIfaces.clear();
266     quotaIfaces.clear();
267     globalAlertBytes = 0;
268     globalAlertTetherCount = 0;
269     sharedQuotaBytes = sharedAlertBytes = 0;
270
271     flushCleanTables(false);
272     res = runCommands(sizeof(IPT_BASIC_ACCOUNTING_COMMANDS) / sizeof(char*),
273             IPT_BASIC_ACCOUNTING_COMMANDS, RunCmdFailureBad);
274
275     return res;
276
277 }
278
279 int BandwidthController::disableBandwidthControl(void) {
280
281     flushCleanTables(false);
282     return 0;
283 }
284
285 int BandwidthController::runCommands(int numCommands, const char *commands[],
286                                      RunCmdErrHandling cmdErrHandling) {
287     int res = 0;
288     IptFailureLog failureLogging = IptFailShow;
289     if (cmdErrHandling == RunCmdFailureOk) {
290         failureLogging = IptFailHide;
291     }
292     ALOGV("runCommands(): %d commands", numCommands);
293     for (int cmdNum = 0; cmdNum < numCommands; cmdNum++) {
294         res = runIpxtablesCmd(commands[cmdNum], IptJumpNoAdd, failureLogging);
295         if (res && cmdErrHandling != RunCmdFailureOk)
296             return res;
297     }
298     return 0;
299 }
300
301 std::string BandwidthController::makeIptablesSpecialAppCmd(IptOp op, int uid, const char *chain) {
302     std::string res;
303     char *buff;
304     const char *opFlag;
305
306     switch (op) {
307     case IptOpInsert:
308         opFlag = "-I";
309         break;
310     case IptOpAppend:
311         ALOGE("Append op not supported for %s uids", chain);
312         res = "";
313         return res;
314         break;
315     case IptOpReplace:
316         opFlag = "-R";
317         break;
318     default:
319     case IptOpDelete:
320         opFlag = "-D";
321         break;
322     }
323     asprintf(&buff, "%s %s -m owner --uid-owner %d", opFlag, chain, uid);
324     res = buff;
325     free(buff);
326     return res;
327 }
328
329 int BandwidthController::enableHappyBox(void) {
330     char cmd[MAX_CMD_LEN];
331     int res = 0;
332
333     /*
334      * We tentatively delete before adding, which helps recovering
335      * from bad states (e.g. netd died).
336      */
337
338     /* Should not exist, but ignore result if already there. */
339     snprintf(cmd, sizeof(cmd), "-N bw_happy_box");
340     runIpxtablesCmd(cmd, IptJumpNoAdd);
341
342     /* Should be empty, but clear in case something was wrong. */
343     snprintf(cmd, sizeof(cmd), "-F bw_happy_box");
344     res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
345
346     snprintf(cmd, sizeof(cmd), "-D bw_penalty_box -j bw_happy_box");
347     runIpxtablesCmd(cmd, IptJumpNoAdd);
348     snprintf(cmd, sizeof(cmd), "-A bw_penalty_box -j bw_happy_box");
349     res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
350
351     /* Whitelist all system apps. */
352     snprintf(cmd, sizeof(cmd),
353             "-A bw_happy_box -m owner --uid-owner %d-%d -j RETURN", 0, MAX_SYSTEM_UID);
354     res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
355
356     /* Reject. Defaulting to prot-unreachable */
357     snprintf(cmd, sizeof(cmd), "-A bw_happy_box -j REJECT");
358     res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
359
360     return res;
361 }
362
363 int BandwidthController::disableHappyBox(void) {
364     char cmd[MAX_CMD_LEN];
365
366     /* Best effort */
367     snprintf(cmd, sizeof(cmd), "-D bw_penalty_box -j bw_happy_box");
368     runIpxtablesCmd(cmd, IptJumpNoAdd);
369     snprintf(cmd, sizeof(cmd), "-F bw_happy_box");
370     runIpxtablesCmd(cmd, IptJumpNoAdd);
371     snprintf(cmd, sizeof(cmd), "-X bw_happy_box");
372     runIpxtablesCmd(cmd, IptJumpNoAdd);
373
374     return 0;
375 }
376
377 int BandwidthController::addNaughtyApps(int numUids, char *appUids[]) {
378     return manipulateNaughtyApps(numUids, appUids, SpecialAppOpAdd);
379 }
380
381 int BandwidthController::removeNaughtyApps(int numUids, char *appUids[]) {
382     return manipulateNaughtyApps(numUids, appUids, SpecialAppOpRemove);
383 }
384
385 int BandwidthController::addNiceApps(int numUids, char *appUids[]) {
386     return manipulateNiceApps(numUids, appUids, SpecialAppOpAdd);
387 }
388
389 int BandwidthController::removeNiceApps(int numUids, char *appUids[]) {
390     return manipulateNiceApps(numUids, appUids, SpecialAppOpRemove);
391 }
392
393 int BandwidthController::manipulateNaughtyApps(int numUids, char *appStrUids[], SpecialAppOp appOp) {
394     return manipulateSpecialApps(numUids, appStrUids, "bw_penalty_box", IptJumpReject, appOp);
395 }
396
397 int BandwidthController::manipulateNiceApps(int numUids, char *appStrUids[], SpecialAppOp appOp) {
398     return manipulateSpecialApps(numUids, appStrUids, "bw_happy_box", IptJumpReturn, appOp);
399 }
400
401
402 int BandwidthController::manipulateSpecialApps(int numUids, char *appStrUids[],
403                                                const char *chain,
404                                                IptJumpOp jumpHandling, SpecialAppOp appOp) {
405
406     int uidNum;
407     const char *failLogTemplate;
408     IptOp op;
409     int appUids[numUids];
410     std::string iptCmd;
411
412     switch (appOp) {
413     case SpecialAppOpAdd:
414         op = IptOpInsert;
415         failLogTemplate = "Failed to add app uid %s(%d) to %s.";
416         break;
417     case SpecialAppOpRemove:
418         op = IptOpDelete;
419         failLogTemplate = "Failed to delete app uid %s(%d) from %s box.";
420         break;
421     default:
422         ALOGE("Unexpected app Op %d", appOp);
423         return -1;
424     }
425
426     for (uidNum = 0; uidNum < numUids; uidNum++) {
427         char *end;
428         appUids[uidNum] = strtoul(appStrUids[uidNum], &end, 0);
429         if (*end || !*appStrUids[uidNum]) {
430             ALOGE(failLogTemplate, appStrUids[uidNum], appUids[uidNum], chain);
431             goto fail_parse;
432         }
433     }
434
435     for (uidNum = 0; uidNum < numUids; uidNum++) {
436         int uid = appUids[uidNum];
437
438         iptCmd = makeIptablesSpecialAppCmd(op, uid, chain);
439         if (runIpxtablesCmd(iptCmd.c_str(), jumpHandling)) {
440             ALOGE(failLogTemplate, appStrUids[uidNum], uid, chain);
441             goto fail_with_uidNum;
442         }
443     }
444     return 0;
445
446 fail_with_uidNum:
447     /* Try to remove the uid that failed in any case*/
448     iptCmd = makeIptablesSpecialAppCmd(IptOpDelete, appUids[uidNum], chain);
449     runIpxtablesCmd(iptCmd.c_str(), jumpHandling);
450 fail_parse:
451     return -1;
452 }
453
454 std::string BandwidthController::makeIptablesQuotaCmd(IptOp op, const char *costName, int64_t quota) {
455     std::string res;
456     char *buff;
457     const char *opFlag;
458
459     ALOGV("makeIptablesQuotaCmd(%d, %" PRId64")", op, quota);
460
461     switch (op) {
462     case IptOpInsert:
463         opFlag = "-I";
464         break;
465     case IptOpAppend:
466         opFlag = "-A";
467         break;
468     case IptOpReplace:
469         opFlag = "-R";
470         break;
471     default:
472     case IptOpDelete:
473         opFlag = "-D";
474         break;
475     }
476
477     // The requried IP version specific --jump REJECT ... will be added later.
478     asprintf(&buff, "%s bw_costly_%s -m quota2 ! --quota %" PRId64" --name %s", opFlag, costName, quota,
479              costName);
480     res = buff;
481     free(buff);
482     return res;
483 }
484
485 int BandwidthController::prepCostlyIface(const char *ifn, QuotaType quotaType) {
486     char cmd[MAX_CMD_LEN];
487     int res = 0, res1, res2;
488     int ruleInsertPos = 1;
489     std::string costString;
490     const char *costCString;
491
492     /* The "-N costly" is created upfront, no need to handle it here. */
493     switch (quotaType) {
494     case QuotaUnique:
495         costString = "bw_costly_";
496         costString += ifn;
497         costCString = costString.c_str();
498         /*
499          * Flush the bw_costly_<iface> is allowed to fail in case it didn't exist.
500          * Creating a new one is allowed to fail in case it existed.
501          * This helps with netd restarts.
502          */
503         snprintf(cmd, sizeof(cmd), "-F %s", costCString);
504         res1 = runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
505         snprintf(cmd, sizeof(cmd), "-N %s", costCString);
506         res2 = runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
507         res = (res1 && res2) || (!res1 && !res2);
508
509         snprintf(cmd, sizeof(cmd), "-A %s -j bw_penalty_box", costCString);
510         res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
511         break;
512     case QuotaShared:
513         costCString = "bw_costly_shared";
514         break;
515     default:
516         ALOGE("Unexpected quotatype %d", quotaType);
517         return -1;
518     }
519
520     if (globalAlertBytes) {
521         /* The alert rule comes 1st */
522         ruleInsertPos = 2;
523     }
524
525     snprintf(cmd, sizeof(cmd), "-D bw_INPUT -i %s --jump %s", ifn, costCString);
526     runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
527
528     snprintf(cmd, sizeof(cmd), "-I bw_INPUT %d -i %s --jump %s", ruleInsertPos, ifn, costCString);
529     res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
530
531     snprintf(cmd, sizeof(cmd), "-D bw_OUTPUT -o %s --jump %s", ifn, costCString);
532     runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
533
534     snprintf(cmd, sizeof(cmd), "-I bw_OUTPUT %d -o %s --jump %s", ruleInsertPos, ifn, costCString);
535     res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
536
537     snprintf(cmd, sizeof(cmd), "-D bw_FORWARD -o %s --jump %s", ifn, costCString);
538     runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
539     snprintf(cmd, sizeof(cmd), "-A bw_FORWARD -o %s --jump %s", ifn, costCString);
540     res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
541
542     return res;
543 }
544
545 int BandwidthController::cleanupCostlyIface(const char *ifn, QuotaType quotaType) {
546     char cmd[MAX_CMD_LEN];
547     int res = 0;
548     std::string costString;
549     const char *costCString;
550
551     switch (quotaType) {
552     case QuotaUnique:
553         costString = "bw_costly_";
554         costString += ifn;
555         costCString = costString.c_str();
556         break;
557     case QuotaShared:
558         costCString = "bw_costly_shared";
559         break;
560     default:
561         ALOGE("Unexpected quotatype %d", quotaType);
562         return -1;
563     }
564
565     snprintf(cmd, sizeof(cmd), "-D bw_INPUT -i %s --jump %s", ifn, costCString);
566     res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
567     for (const auto tableName : {LOCAL_OUTPUT, LOCAL_FORWARD}) {
568         snprintf(cmd, sizeof(cmd), "-D %s -o %s --jump %s", tableName, ifn, costCString);
569         res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
570     }
571
572     /* The "-N bw_costly_shared" is created upfront, no need to handle it here. */
573     if (quotaType == QuotaUnique) {
574         snprintf(cmd, sizeof(cmd), "-F %s", costCString);
575         res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
576         snprintf(cmd, sizeof(cmd), "-X %s", costCString);
577         res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
578     }
579     return res;
580 }
581
582 int BandwidthController::setInterfaceSharedQuota(const char *iface, int64_t maxBytes) {
583     char ifn[MAX_IFACENAME_LEN];
584     int res = 0;
585     std::string quotaCmd;
586     std::string ifaceName;
587     ;
588     const char *costName = "shared";
589     std::list<std::string>::iterator it;
590
591     if (!maxBytes) {
592         /* Don't talk about -1, deprecate it. */
593         ALOGE("Invalid bytes value. 1..max_int64.");
594         return -1;
595     }
596     if (!isIfaceName(iface))
597         return -1;
598     if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
599         ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
600         return -1;
601     }
602     ifaceName = ifn;
603
604     if (maxBytes == -1) {
605         return removeInterfaceSharedQuota(ifn);
606     }
607
608     /* Insert ingress quota. */
609     for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) {
610         if (*it == ifaceName)
611             break;
612     }
613
614     if (it == sharedQuotaIfaces.end()) {
615         res |= prepCostlyIface(ifn, QuotaShared);
616         if (sharedQuotaIfaces.empty()) {
617             quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes);
618             res |= runIpxtablesCmd(quotaCmd.c_str(), IptJumpReject);
619             if (res) {
620                 ALOGE("Failed set quota rule");
621                 goto fail;
622             }
623             sharedQuotaBytes = maxBytes;
624         }
625         sharedQuotaIfaces.push_front(ifaceName);
626
627     }
628
629     if (maxBytes != sharedQuotaBytes) {
630         res |= updateQuota(costName, maxBytes);
631         if (res) {
632             ALOGE("Failed update quota for %s", costName);
633             goto fail;
634         }
635         sharedQuotaBytes = maxBytes;
636     }
637     return 0;
638
639     fail:
640     /*
641      * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
642      * rules in the kernel to see which ones need cleaning up.
643      * For now callers needs to choose if they want to "ndc bandwidth enable"
644      * which resets everything.
645      */
646     removeInterfaceSharedQuota(ifn);
647     return -1;
648 }
649
650 /* It will also cleanup any shared alerts */
651 int BandwidthController::removeInterfaceSharedQuota(const char *iface) {
652     char ifn[MAX_IFACENAME_LEN];
653     int res = 0;
654     std::string ifaceName;
655     std::list<std::string>::iterator it;
656     const char *costName = "shared";
657
658     if (!isIfaceName(iface))
659         return -1;
660     if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
661         ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
662         return -1;
663     }
664     ifaceName = ifn;
665
666     for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) {
667         if (*it == ifaceName)
668             break;
669     }
670     if (it == sharedQuotaIfaces.end()) {
671         ALOGE("No such iface %s to delete", ifn);
672         return -1;
673     }
674
675     res |= cleanupCostlyIface(ifn, QuotaShared);
676     sharedQuotaIfaces.erase(it);
677
678     if (sharedQuotaIfaces.empty()) {
679         std::string quotaCmd;
680         quotaCmd = makeIptablesQuotaCmd(IptOpDelete, costName, sharedQuotaBytes);
681         res |= runIpxtablesCmd(quotaCmd.c_str(), IptJumpReject);
682         sharedQuotaBytes = 0;
683         if (sharedAlertBytes) {
684             removeSharedAlert();
685             sharedAlertBytes = 0;
686         }
687     }
688     return res;
689 }
690
691 int BandwidthController::setInterfaceQuota(const char *iface, int64_t maxBytes) {
692     char ifn[MAX_IFACENAME_LEN];
693     int res = 0;
694     std::string ifaceName;
695     const char *costName;
696     std::list<QuotaInfo>::iterator it;
697     std::string quotaCmd;
698
699     if (!isIfaceName(iface))
700         return -1;
701
702     if (!maxBytes) {
703         /* Don't talk about -1, deprecate it. */
704         ALOGE("Invalid bytes value. 1..max_int64.");
705         return -1;
706     }
707     if (maxBytes == -1) {
708         return removeInterfaceQuota(iface);
709     }
710
711     if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
712         ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
713         return -1;
714     }
715     ifaceName = ifn;
716     costName = iface;
717
718     /* Insert ingress quota. */
719     for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
720         if (it->ifaceName == ifaceName)
721             break;
722     }
723
724     if (it == quotaIfaces.end()) {
725         /* Preparing the iface adds a penalty/happy box check */
726         res |= prepCostlyIface(ifn, QuotaUnique);
727         /*
728          * The rejecting quota limit should go after the penalty/happy box checks
729          * or else a naughty app could just eat up the quota.
730          * So we append here.
731          */
732         quotaCmd = makeIptablesQuotaCmd(IptOpAppend, costName, maxBytes);
733         res |= runIpxtablesCmd(quotaCmd.c_str(), IptJumpReject);
734         if (res) {
735             ALOGE("Failed set quota rule");
736             goto fail;
737         }
738
739         quotaIfaces.push_front(QuotaInfo(ifaceName, maxBytes, 0));
740
741     } else {
742         res |= updateQuota(costName, maxBytes);
743         if (res) {
744             ALOGE("Failed update quota for %s", iface);
745             goto fail;
746         }
747         it->quota = maxBytes;
748     }
749     return 0;
750
751     fail:
752     /*
753      * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
754      * rules in the kernel to see which ones need cleaning up.
755      * For now callers needs to choose if they want to "ndc bandwidth enable"
756      * which resets everything.
757      */
758     removeInterfaceSharedQuota(ifn);
759     return -1;
760 }
761
762 int BandwidthController::getInterfaceSharedQuota(int64_t *bytes) {
763     return getInterfaceQuota("shared", bytes);
764 }
765
766 int BandwidthController::getInterfaceQuota(const char *costName, int64_t *bytes) {
767     FILE *fp;
768     char *fname;
769     int scanRes;
770
771     if (!isIfaceName(costName))
772         return -1;
773
774     asprintf(&fname, "/proc/net/xt_quota/%s", costName);
775     fp = fopen(fname, "re");
776     free(fname);
777     if (!fp) {
778         ALOGE("Reading quota %s failed (%s)", costName, strerror(errno));
779         return -1;
780     }
781     scanRes = fscanf(fp, "%" SCNd64, bytes);
782     ALOGV("Read quota res=%d bytes=%" PRId64, scanRes, *bytes);
783     fclose(fp);
784     return scanRes == 1 ? 0 : -1;
785 }
786
787 int BandwidthController::removeInterfaceQuota(const char *iface) {
788
789     char ifn[MAX_IFACENAME_LEN];
790     int res = 0;
791     std::string ifaceName;
792     std::list<QuotaInfo>::iterator it;
793
794     if (!isIfaceName(iface))
795         return -1;
796     if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
797         ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
798         return -1;
799     }
800     ifaceName = ifn;
801
802     for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
803         if (it->ifaceName == ifaceName)
804             break;
805     }
806
807     if (it == quotaIfaces.end()) {
808         ALOGE("No such iface %s to delete", ifn);
809         return -1;
810     }
811
812     /* This also removes the quota command of CostlyIface chain. */
813     res |= cleanupCostlyIface(ifn, QuotaUnique);
814
815     quotaIfaces.erase(it);
816
817     return res;
818 }
819
820 int BandwidthController::updateQuota(const char *quotaName, int64_t bytes) {
821     FILE *fp;
822     char *fname;
823
824     if (!isIfaceName(quotaName)) {
825         ALOGE("updateQuota: Invalid quotaName \"%s\"", quotaName);
826         return -1;
827     }
828
829     asprintf(&fname, "/proc/net/xt_quota/%s", quotaName);
830     fp = fopen(fname, "we");
831     free(fname);
832     if (!fp) {
833         ALOGE("Updating quota %s failed (%s)", quotaName, strerror(errno));
834         return -1;
835     }
836     fprintf(fp, "%" PRId64"\n", bytes);
837     fclose(fp);
838     return 0;
839 }
840
841 int 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;
850     case IptOpAppend:
851         opFlag = "-A";
852         break;
853     case IptOpReplace:
854         opFlag = "-R";
855         break;
856     default:
857     case IptOpDelete:
858         opFlag = "-D";
859         break;
860     }
861
862     asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_INPUT",
863         bytes, alertName);
864     res |= runIpxtablesCmd(alertQuotaCmd, IptJumpNoAdd);
865     free(alertQuotaCmd);
866     asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_OUTPUT",
867         bytes, alertName);
868     res |= runIpxtablesCmd(alertQuotaCmd, IptJumpNoAdd);
869     free(alertQuotaCmd);
870     return res;
871 }
872
873 int BandwidthController::runIptablesAlertFwdCmd(IptOp op, const char *alertName, int64_t bytes) {
874     int res = 0;
875     const char *opFlag;
876     char *alertQuotaCmd;
877
878     switch (op) {
879     case IptOpInsert:
880         opFlag = "-I";
881         break;
882     case IptOpAppend:
883         opFlag = "-A";
884         break;
885     case IptOpReplace:
886         opFlag = "-R";
887         break;
888     default:
889     case IptOpDelete:
890         opFlag = "-D";
891         break;
892     }
893
894     asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_FORWARD",
895         bytes, alertName);
896     res = runIpxtablesCmd(alertQuotaCmd, IptJumpNoAdd);
897     free(alertQuotaCmd);
898     return res;
899 }
900
901 int BandwidthController::setGlobalAlert(int64_t bytes) {
902     const char *alertName = ALERT_GLOBAL_NAME;
903     int res = 0;
904
905     if (!bytes) {
906         ALOGE("Invalid bytes value. 1..max_int64.");
907         return -1;
908     }
909     if (globalAlertBytes) {
910         res = updateQuota(alertName, bytes);
911     } else {
912         res = runIptablesAlertCmd(IptOpInsert, alertName, bytes);
913         if (globalAlertTetherCount) {
914             ALOGV("setGlobalAlert for %d tether", globalAlertTetherCount);
915             res |= runIptablesAlertFwdCmd(IptOpInsert, alertName, bytes);
916         }
917     }
918     globalAlertBytes = bytes;
919     return res;
920 }
921
922 int BandwidthController::setGlobalAlertInForwardChain(void) {
923     const char *alertName = ALERT_GLOBAL_NAME;
924     int res = 0;
925
926     globalAlertTetherCount++;
927     ALOGV("setGlobalAlertInForwardChain(): %d tether", globalAlertTetherCount);
928
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
943 int BandwidthController::removeGlobalAlert(void) {
944
945     const char *alertName = ALERT_GLOBAL_NAME;
946     int res = 0;
947
948     if (!globalAlertBytes) {
949         ALOGE("No prior alert set");
950         return -1;
951     }
952     res = runIptablesAlertCmd(IptOpDelete, alertName, globalAlertBytes);
953     if (globalAlertTetherCount) {
954         res |= runIptablesAlertFwdCmd(IptOpDelete, alertName, globalAlertBytes);
955     }
956     globalAlertBytes = 0;
957     return res;
958 }
959
960 int BandwidthController::removeGlobalAlertInForwardChain(void) {
961     int res = 0;
962     const char *alertName = ALERT_GLOBAL_NAME;
963
964     if (!globalAlertTetherCount) {
965         ALOGE("No prior alert set");
966         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
984 int BandwidthController::setSharedAlert(int64_t bytes) {
985     if (!sharedQuotaBytes) {
986         ALOGE("Need to have a prior shared quota set to set an alert");
987         return -1;
988     }
989     if (!bytes) {
990         ALOGE("Invalid bytes value. 1..max_int64.");
991         return -1;
992     }
993     return setCostlyAlert("shared", bytes, &sharedAlertBytes);
994 }
995
996 int BandwidthController::removeSharedAlert(void) {
997     return removeCostlyAlert("shared", &sharedAlertBytes);
998 }
999
1000 int BandwidthController::setInterfaceAlert(const char *iface, int64_t bytes) {
1001     std::list<QuotaInfo>::iterator it;
1002
1003     if (!isIfaceName(iface)) {
1004         ALOGE("setInterfaceAlert: Invalid iface \"%s\"", iface);
1005         return -1;
1006     }
1007
1008     if (!bytes) {
1009         ALOGE("Invalid bytes value. 1..max_int64.");
1010         return -1;
1011     }
1012     for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
1013         if (it->ifaceName == iface)
1014             break;
1015     }
1016
1017     if (it == quotaIfaces.end()) {
1018         ALOGE("Need to have a prior interface quota set to set an alert");
1019         return -1;
1020     }
1021
1022     return setCostlyAlert(iface, bytes, &it->alert);
1023 }
1024
1025 int BandwidthController::removeInterfaceAlert(const char *iface) {
1026     std::list<QuotaInfo>::iterator it;
1027
1028     if (!isIfaceName(iface)) {
1029         ALOGE("removeInterfaceAlert: Invalid iface \"%s\"", iface);
1030         return -1;
1031     }
1032
1033     for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
1034         if (it->ifaceName == iface)
1035             break;
1036     }
1037
1038     if (it == quotaIfaces.end()) {
1039         ALOGE("No prior alert set for interface %s", iface);
1040         return -1;
1041     }
1042
1043     return removeCostlyAlert(iface, &it->alert);
1044 }
1045
1046 int BandwidthController::setCostlyAlert(const char *costName, int64_t bytes, int64_t *alertBytes) {
1047     char *alertQuotaCmd;
1048     char *chainName;
1049     int res = 0;
1050     char *alertName;
1051
1052     if (!isIfaceName(costName)) {
1053         ALOGE("setCostlyAlert: Invalid costName \"%s\"", costName);
1054         return -1;
1055     }
1056
1057     if (!bytes) {
1058         ALOGE("Invalid bytes value. 1..max_int64.");
1059         return -1;
1060     }
1061     asprintf(&alertName, "%sAlert", costName);
1062     if (*alertBytes) {
1063         res = updateQuota(alertName, *alertBytes);
1064     } else {
1065         asprintf(&chainName, "bw_costly_%s", costName);
1066         asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "-A", chainName, bytes, alertName);
1067         res |= runIpxtablesCmd(alertQuotaCmd, IptJumpNoAdd);
1068         free(alertQuotaCmd);
1069         free(chainName);
1070     }
1071     *alertBytes = bytes;
1072     free(alertName);
1073     return res;
1074 }
1075
1076 int BandwidthController::removeCostlyAlert(const char *costName, int64_t *alertBytes) {
1077     char *alertQuotaCmd;
1078     char *chainName;
1079     char *alertName;
1080     int res = 0;
1081
1082     if (!isIfaceName(costName)) {
1083         ALOGE("removeCostlyAlert: Invalid costName \"%s\"", costName);
1084         return -1;
1085     }
1086
1087     if (!*alertBytes) {
1088         ALOGE("No prior alert set for %s alert", costName);
1089         return -1;
1090     }
1091
1092     asprintf(&alertName, "%sAlert", costName);
1093     asprintf(&chainName, "bw_costly_%s", costName);
1094     asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "-D", chainName, *alertBytes, alertName);
1095     res |= runIpxtablesCmd(alertQuotaCmd, IptJumpNoAdd);
1096     free(alertQuotaCmd);
1097     free(chainName);
1098
1099     *alertBytes = 0;
1100     free(alertName);
1101     return res;
1102 }
1103
1104 /*
1105  * Parse the ptks and bytes out of:
1106  *   Chain natctrl_tether_counters (4 references)
1107  *       pkts      bytes target     prot opt in     out     source               destination
1108  *         26     2373 RETURN     all  --  wlan0  rmnet0  0.0.0.0/0            0.0.0.0/0
1109  *         27     2002 RETURN     all  --  rmnet0 wlan0   0.0.0.0/0            0.0.0.0/0
1110  *       1040   107471 RETURN     all  --  bt-pan rmnet0  0.0.0.0/0            0.0.0.0/0
1111  *       1450  1708806 RETURN     all  --  rmnet0 bt-pan  0.0.0.0/0            0.0.0.0/0
1112  * It results in an error if invoked and no tethering counter rules exist. The constraint
1113  * helps detect complete parsing failure.
1114  */
1115 int BandwidthController::parseForwardChainStats(SocketClient *cli, const TetherStats filter,
1116                                                 FILE *fp, std::string &extraProcessingInfo) {
1117     int res;
1118     char lineBuffer[MAX_IPT_OUTPUT_LINE_LEN];
1119     char iface0[MAX_IPT_OUTPUT_LINE_LEN];
1120     char iface1[MAX_IPT_OUTPUT_LINE_LEN];
1121     char rest[MAX_IPT_OUTPUT_LINE_LEN];
1122
1123     TetherStats stats;
1124     char *buffPtr;
1125     int64_t packets, bytes;
1126     int statsFound = 0;
1127
1128     bool filterPair = filter.intIface[0] && filter.extIface[0];
1129
1130     char *filterMsg = filter.getStatsLine();
1131     ALOGV("filter: %s",  filterMsg);
1132     free(filterMsg);
1133
1134     stats = filter;
1135
1136     while (NULL != (buffPtr = fgets(lineBuffer, MAX_IPT_OUTPUT_LINE_LEN, fp))) {
1137         /* Clean up, so a failed parse can still print info */
1138         iface0[0] = iface1[0] = rest[0] = packets = bytes = 0;
1139         res = sscanf(buffPtr, "%" SCNd64" %" SCNd64" RETURN all -- %s %s 0.%s",
1140                 &packets, &bytes, iface0, iface1, rest);
1141         ALOGV("parse res=%d iface0=<%s> iface1=<%s> pkts=%" PRId64" bytes=%" PRId64" rest=<%s> orig line=<%s>", res,
1142              iface0, iface1, packets, bytes, rest, buffPtr);
1143         extraProcessingInfo += buffPtr;
1144
1145         if (res != 5) {
1146             continue;
1147         }
1148         /*
1149          * The following assumes that the 1st rule has in:extIface out:intIface,
1150          * which is what NatController sets up.
1151          * If not filtering, the 1st match rx, and sets up the pair for the tx side.
1152          */
1153         if (filter.intIface[0] && filter.extIface[0]) {
1154             if (filter.intIface == iface0 && filter.extIface == iface1) {
1155                 ALOGV("2Filter RX iface_in=%s iface_out=%s rx_bytes=%" PRId64" rx_packets=%" PRId64" ", iface0, iface1, bytes, packets);
1156                 stats.rxPackets = packets;
1157                 stats.rxBytes = bytes;
1158             } else if (filter.intIface == iface1 && filter.extIface == iface0) {
1159                 ALOGV("2Filter TX iface_in=%s iface_out=%s rx_bytes=%" PRId64" rx_packets=%" PRId64" ", iface0, iface1, bytes, packets);
1160                 stats.txPackets = packets;
1161                 stats.txBytes = bytes;
1162             }
1163         } else if (filter.intIface[0] || filter.extIface[0]) {
1164             if (filter.intIface == iface0 || filter.extIface == iface1) {
1165                 ALOGV("1Filter RX iface_in=%s iface_out=%s rx_bytes=%" PRId64" rx_packets=%" PRId64" ", iface0, iface1, bytes, packets);
1166                 stats.intIface = iface0;
1167                 stats.extIface = iface1;
1168                 stats.rxPackets = packets;
1169                 stats.rxBytes = bytes;
1170             } else if (filter.intIface == iface1 || filter.extIface == iface0) {
1171                 ALOGV("1Filter TX iface_in=%s iface_out=%s rx_bytes=%" PRId64" rx_packets=%" PRId64" ", iface0, iface1, bytes, packets);
1172                 stats.intIface = iface1;
1173                 stats.extIface = iface0;
1174                 stats.txPackets = packets;
1175                 stats.txBytes = bytes;
1176             }
1177         } else /* if (!filter.intFace[0] && !filter.extIface[0]) */ {
1178             if (!stats.intIface[0]) {
1179                 ALOGV("0Filter RX iface_in=%s iface_out=%s rx_bytes=%" PRId64" rx_packets=%" PRId64" ", iface0, iface1, bytes, packets);
1180                 stats.intIface = iface0;
1181                 stats.extIface = iface1;
1182                 stats.rxPackets = packets;
1183                 stats.rxBytes = bytes;
1184             } else if (stats.intIface == iface1 && stats.extIface == iface0) {
1185                 ALOGV("0Filter TX iface_in=%s iface_out=%s rx_bytes=%" PRId64" rx_packets=%" PRId64" ", iface0, iface1, bytes, packets);
1186                 stats.txPackets = packets;
1187                 stats.txBytes = bytes;
1188             }
1189         }
1190         if (stats.rxBytes != -1 && stats.txBytes != -1) {
1191             ALOGV("rx_bytes=%" PRId64" tx_bytes=%" PRId64" filterPair=%d", stats.rxBytes, stats.txBytes, filterPair);
1192             /* Send out stats, and prep for the next if needed. */
1193             char *msg = stats.getStatsLine();
1194             if (filterPair) {
1195                 cli->sendMsg(ResponseCode::TetheringStatsResult, msg, false);
1196                 return 0;
1197             } else {
1198                 cli->sendMsg(ResponseCode::TetheringStatsListResult, msg, false);
1199                 stats = filter;
1200             }
1201             free(msg);
1202             statsFound++;
1203         }
1204     }
1205
1206     /* It is always an error to find only one side of the stats. */
1207     /* It is an error to find nothing when not filtering. */
1208     if (((stats.rxBytes == -1) != (stats.txBytes == -1)) ||
1209         (!statsFound && !filterPair)) {
1210         return -1;
1211     }
1212     cli->sendMsg(ResponseCode::CommandOkay, "Tethering stats list completed", false);
1213     return 0;
1214 }
1215
1216 char *BandwidthController::TetherStats::getStatsLine(void) const {
1217     char *msg;
1218     asprintf(&msg, "%s %s %" PRId64" %" PRId64" %" PRId64" %" PRId64, intIface.c_str(), extIface.c_str(),
1219             rxBytes, rxPackets, txBytes, txPackets);
1220     return msg;
1221 }
1222
1223 int BandwidthController::getTetherStats(SocketClient *cli, TetherStats &stats, std::string &extraProcessingInfo) {
1224     int res;
1225     std::string fullCmd;
1226     FILE *iptOutput;
1227
1228     /*
1229      * Why not use some kind of lib to talk to iptables?
1230      * Because the only libs are libiptc and libip6tc in iptables, and they are
1231      * not easy to use. They require the known iptables match modules to be
1232      * preloaded/linked, and require apparently a lot of wrapper code to get
1233      * the wanted info.
1234      */
1235     fullCmd = IPTABLES_PATH;
1236     fullCmd += " -nvx -w -L ";
1237     fullCmd += NatController::LOCAL_TETHER_COUNTERS_CHAIN;
1238     iptOutput = popen(fullCmd.c_str(), "r");
1239     if (!iptOutput) {
1240             ALOGE("Failed to run %s err=%s", fullCmd.c_str(), strerror(errno));
1241             extraProcessingInfo += "Failed to run iptables.";
1242         return -1;
1243     }
1244     res = parseForwardChainStats(cli, stats, iptOutput, extraProcessingInfo);
1245     pclose(iptOutput);
1246
1247     /* Currently NatController doesn't do ipv6 tethering, so we are done. */
1248     return res;
1249 }
1250
1251 void BandwidthController::flushExistingCostlyTables(bool doClean) {
1252     std::string fullCmd;
1253     FILE *iptOutput;
1254
1255     /* Only lookup ip4 table names as ip6 will have the same tables ... */
1256     fullCmd = IPTABLES_PATH;
1257     fullCmd += " -w -S";
1258     iptOutput = popen(fullCmd.c_str(), "r");
1259     if (!iptOutput) {
1260             ALOGE("Failed to run %s err=%s", fullCmd.c_str(), strerror(errno));
1261         return;
1262     }
1263     /* ... then flush/clean both ip4 and ip6 iptables. */
1264     parseAndFlushCostlyTables(iptOutput, doClean);
1265     pclose(iptOutput);
1266 }
1267
1268 void BandwidthController::parseAndFlushCostlyTables(FILE *fp, bool doRemove) {
1269     int res;
1270     char lineBuffer[MAX_IPT_OUTPUT_LINE_LEN];
1271     char costlyIfaceName[MAX_IPT_OUTPUT_LINE_LEN];
1272     char cmd[MAX_CMD_LEN];
1273     char *buffPtr;
1274
1275     while (NULL != (buffPtr = fgets(lineBuffer, MAX_IPT_OUTPUT_LINE_LEN, fp))) {
1276         costlyIfaceName[0] = '\0';   /* So that debugging output always works */
1277         res = sscanf(buffPtr, "-N bw_costly_%s", costlyIfaceName);
1278         ALOGV("parse res=%d costly=<%s> orig line=<%s>", res,
1279             costlyIfaceName, buffPtr);
1280         if (res != 1) {
1281             continue;
1282         }
1283         /* Exclusions: "shared" is not an ifacename */
1284         if (!strcmp(costlyIfaceName, "shared")) {
1285             continue;
1286         }
1287
1288         snprintf(cmd, sizeof(cmd), "-F bw_costly_%s", costlyIfaceName);
1289         runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
1290         if (doRemove) {
1291             snprintf(cmd, sizeof(cmd), "-X bw_costly_%s", costlyIfaceName);
1292             runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
1293         }
1294     }
1295 }