OSDN Git Service

am 93e6f6a7: Merge "Make iptables -L and -S calls wait for xtables lock"
[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     naughtyAppUids.clear();
268     niceAppUids.clear();
269     globalAlertBytes = 0;
270     globalAlertTetherCount = 0;
271     sharedQuotaBytes = sharedAlertBytes = 0;
272
273     flushCleanTables(false);
274     res = runCommands(sizeof(IPT_BASIC_ACCOUNTING_COMMANDS) / sizeof(char*),
275             IPT_BASIC_ACCOUNTING_COMMANDS, RunCmdFailureBad);
276
277     return res;
278
279 }
280
281 int BandwidthController::disableBandwidthControl(void) {
282
283     flushCleanTables(false);
284     return 0;
285 }
286
287 int BandwidthController::runCommands(int numCommands, const char *commands[],
288                                      RunCmdErrHandling cmdErrHandling) {
289     int res = 0;
290     IptFailureLog failureLogging = IptFailShow;
291     if (cmdErrHandling == RunCmdFailureOk) {
292         failureLogging = IptFailHide;
293     }
294     ALOGV("runCommands(): %d commands", numCommands);
295     for (int cmdNum = 0; cmdNum < numCommands; cmdNum++) {
296         res = runIpxtablesCmd(commands[cmdNum], IptJumpNoAdd, failureLogging);
297         if (res && cmdErrHandling != RunCmdFailureOk)
298             return res;
299     }
300     return 0;
301 }
302
303 std::string BandwidthController::makeIptablesSpecialAppCmd(IptOp op, int uid, const char *chain) {
304     std::string res;
305     char *buff;
306     const char *opFlag;
307
308     switch (op) {
309     case IptOpInsert:
310         opFlag = "-I";
311         break;
312     case IptOpAppend:
313         ALOGE("Append op not supported for %s uids", chain);
314         res = "";
315         return res;
316         break;
317     case IptOpReplace:
318         opFlag = "-R";
319         break;
320     default:
321     case IptOpDelete:
322         opFlag = "-D";
323         break;
324     }
325     asprintf(&buff, "%s %s -m owner --uid-owner %d", opFlag, chain, uid);
326     res = buff;
327     free(buff);
328     return res;
329 }
330
331 int BandwidthController::enableHappyBox(void) {
332     char cmd[MAX_CMD_LEN];
333     int res = 0;
334
335     /*
336      * We tentatively delete before adding, which helps recovering
337      * from bad states (e.g. netd died).
338      */
339
340     /* Should not exist, but ignore result if already there. */
341     snprintf(cmd, sizeof(cmd), "-N bw_happy_box");
342     runIpxtablesCmd(cmd, IptJumpNoAdd);
343
344     /* Should be empty, but clear in case something was wrong. */
345     niceAppUids.clear();
346     snprintf(cmd, sizeof(cmd), "-F bw_happy_box");
347     res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
348
349     snprintf(cmd, sizeof(cmd), "-D bw_penalty_box -j bw_happy_box");
350     runIpxtablesCmd(cmd, IptJumpNoAdd);
351     snprintf(cmd, sizeof(cmd), "-A bw_penalty_box -j bw_happy_box");
352     res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
353
354     /* Reject. Defaulting to prot-unreachable */
355     snprintf(cmd, sizeof(cmd), "-D bw_happy_box -j REJECT");
356     runIpxtablesCmd(cmd, IptJumpNoAdd);
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     niceAppUids.clear();
370     snprintf(cmd, sizeof(cmd), "-F bw_happy_box");
371     runIpxtablesCmd(cmd, IptJumpNoAdd);
372     snprintf(cmd, sizeof(cmd), "-X bw_happy_box");
373     runIpxtablesCmd(cmd, IptJumpNoAdd);
374
375     return 0;
376 }
377
378 int BandwidthController::addNaughtyApps(int numUids, char *appUids[]) {
379     return manipulateNaughtyApps(numUids, appUids, SpecialAppOpAdd);
380 }
381
382 int BandwidthController::removeNaughtyApps(int numUids, char *appUids[]) {
383     return manipulateNaughtyApps(numUids, appUids, SpecialAppOpRemove);
384 }
385
386 int BandwidthController::addNiceApps(int numUids, char *appUids[]) {
387     return manipulateNiceApps(numUids, appUids, SpecialAppOpAdd);
388 }
389
390 int BandwidthController::removeNiceApps(int numUids, char *appUids[]) {
391     return manipulateNiceApps(numUids, appUids, SpecialAppOpRemove);
392 }
393
394 int BandwidthController::manipulateNaughtyApps(int numUids, char *appStrUids[], SpecialAppOp appOp) {
395     return manipulateSpecialApps(numUids, appStrUids, "bw_penalty_box", naughtyAppUids, IptJumpReject, appOp);
396 }
397
398 int BandwidthController::manipulateNiceApps(int numUids, char *appStrUids[], SpecialAppOp appOp) {
399     return manipulateSpecialApps(numUids, appStrUids, "bw_happy_box", niceAppUids, IptJumpReturn, appOp);
400 }
401
402
403 int BandwidthController::manipulateSpecialApps(int numUids, char *appStrUids[],
404                                                const char *chain,
405                                                std::list<int /*appUid*/> &specialAppUids,
406                                                IptJumpOp jumpHandling, SpecialAppOp appOp) {
407
408     int uidNum;
409     const char *failLogTemplate;
410     IptOp op;
411     int appUids[numUids];
412     std::string iptCmd;
413     std::list<int /*uid*/>::iterator it;
414
415     switch (appOp) {
416     case SpecialAppOpAdd:
417         op = IptOpInsert;
418         failLogTemplate = "Failed to add app uid %s(%d) to %s.";
419         break;
420     case SpecialAppOpRemove:
421         op = IptOpDelete;
422         failLogTemplate = "Failed to delete app uid %s(%d) from %s box.";
423         break;
424     default:
425         ALOGE("Unexpected app Op %d", appOp);
426         return -1;
427     }
428
429     for (uidNum = 0; uidNum < numUids; uidNum++) {
430         char *end;
431         appUids[uidNum] = strtoul(appStrUids[uidNum], &end, 0);
432         if (*end || !*appStrUids[uidNum]) {
433             ALOGE(failLogTemplate, appStrUids[uidNum], appUids[uidNum], chain);
434             goto fail_parse;
435         }
436     }
437
438     for (uidNum = 0; uidNum < numUids; uidNum++) {
439         int uid = appUids[uidNum];
440         for (it = specialAppUids.begin(); it != specialAppUids.end(); it++) {
441             if (*it == uid)
442                 break;
443         }
444         bool found = (it != specialAppUids.end());
445
446         if (appOp == SpecialAppOpRemove) {
447             if (!found) {
448                 ALOGE("No such appUid %d to remove", uid);
449                 return -1;
450             }
451             specialAppUids.erase(it);
452         } else {
453             if (found) {
454                 ALOGE("appUid %d exists already", uid);
455                 return -1;
456             }
457             specialAppUids.push_front(uid);
458         }
459
460         iptCmd = makeIptablesSpecialAppCmd(op, uid, chain);
461         if (runIpxtablesCmd(iptCmd.c_str(), jumpHandling)) {
462             ALOGE(failLogTemplate, appStrUids[uidNum], uid, chain);
463             goto fail_with_uidNum;
464         }
465     }
466     return 0;
467
468 fail_with_uidNum:
469     /* Try to remove the uid that failed in any case*/
470     iptCmd = makeIptablesSpecialAppCmd(IptOpDelete, appUids[uidNum], chain);
471     runIpxtablesCmd(iptCmd.c_str(), jumpHandling);
472 fail_parse:
473     return -1;
474 }
475
476 std::string BandwidthController::makeIptablesQuotaCmd(IptOp op, const char *costName, int64_t quota) {
477     std::string res;
478     char *buff;
479     const char *opFlag;
480
481     ALOGV("makeIptablesQuotaCmd(%d, %" PRId64")", op, quota);
482
483     switch (op) {
484     case IptOpInsert:
485         opFlag = "-I";
486         break;
487     case IptOpAppend:
488         opFlag = "-A";
489         break;
490     case IptOpReplace:
491         opFlag = "-R";
492         break;
493     default:
494     case IptOpDelete:
495         opFlag = "-D";
496         break;
497     }
498
499     // The requried IP version specific --jump REJECT ... will be added later.
500     asprintf(&buff, "%s bw_costly_%s -m quota2 ! --quota %" PRId64" --name %s", opFlag, costName, quota,
501              costName);
502     res = buff;
503     free(buff);
504     return res;
505 }
506
507 int BandwidthController::prepCostlyIface(const char *ifn, QuotaType quotaType) {
508     char cmd[MAX_CMD_LEN];
509     int res = 0, res1, res2;
510     int ruleInsertPos = 1;
511     std::string costString;
512     const char *costCString;
513
514     /* The "-N costly" is created upfront, no need to handle it here. */
515     switch (quotaType) {
516     case QuotaUnique:
517         costString = "bw_costly_";
518         costString += ifn;
519         costCString = costString.c_str();
520         /*
521          * Flush the bw_costly_<iface> is allowed to fail in case it didn't exist.
522          * 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);
526         res1 = runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
527         snprintf(cmd, sizeof(cmd), "-N %s", costCString);
528         res2 = runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
529         res = (res1 && res2) || (!res1 && !res2);
530
531         snprintf(cmd, sizeof(cmd), "-A %s -j bw_penalty_box", costCString);
532         res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
533         break;
534     case QuotaShared:
535         costCString = "bw_costly_shared";
536         break;
537     default:
538         ALOGE("Unexpected quotatype %d", quotaType);
539         return -1;
540     }
541
542     if (globalAlertBytes) {
543         /* The alert rule comes 1st */
544         ruleInsertPos = 2;
545     }
546
547     snprintf(cmd, sizeof(cmd), "-D bw_INPUT -i %s --jump %s", ifn, costCString);
548     runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
549
550     snprintf(cmd, sizeof(cmd), "-I bw_INPUT %d -i %s --jump %s", ruleInsertPos, ifn, costCString);
551     res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
552
553     snprintf(cmd, sizeof(cmd), "-D bw_OUTPUT -o %s --jump %s", ifn, costCString);
554     runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
555
556     snprintf(cmd, sizeof(cmd), "-I bw_OUTPUT %d -o %s --jump %s", ruleInsertPos, ifn, costCString);
557     res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
558     return res;
559 }
560
561 int BandwidthController::cleanupCostlyIface(const char *ifn, QuotaType quotaType) {
562     char cmd[MAX_CMD_LEN];
563     int res = 0;
564     std::string costString;
565     const char *costCString;
566
567     switch (quotaType) {
568     case QuotaUnique:
569         costString = "bw_costly_";
570         costString += ifn;
571         costCString = costString.c_str();
572         break;
573     case QuotaShared:
574         costCString = "bw_costly_shared";
575         break;
576     default:
577         ALOGE("Unexpected quotatype %d", quotaType);
578         return -1;
579     }
580
581     snprintf(cmd, sizeof(cmd), "-D bw_INPUT -i %s --jump %s", ifn, costCString);
582     res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
583     snprintf(cmd, sizeof(cmd), "-D bw_OUTPUT -o %s --jump %s", ifn, costCString);
584     res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
585
586     /* The "-N bw_costly_shared" is created upfront, no need to handle it here. */
587     if (quotaType == QuotaUnique) {
588         snprintf(cmd, sizeof(cmd), "-F %s", costCString);
589         res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
590         snprintf(cmd, sizeof(cmd), "-X %s", costCString);
591         res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
592     }
593     return res;
594 }
595
596 int BandwidthController::setInterfaceSharedQuota(const char *iface, int64_t maxBytes) {
597     char ifn[MAX_IFACENAME_LEN];
598     int res = 0;
599     std::string quotaCmd;
600     std::string ifaceName;
601     ;
602     const char *costName = "shared";
603     std::list<std::string>::iterator it;
604
605     if (!maxBytes) {
606         /* Don't talk about -1, deprecate it. */
607         ALOGE("Invalid bytes value. 1..max_int64.");
608         return -1;
609     }
610     if (!isIfaceName(iface))
611         return -1;
612     if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
613         ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
614         return -1;
615     }
616     ifaceName = ifn;
617
618     if (maxBytes == -1) {
619         return removeInterfaceSharedQuota(ifn);
620     }
621
622     /* Insert ingress quota. */
623     for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) {
624         if (*it == ifaceName)
625             break;
626     }
627
628     if (it == sharedQuotaIfaces.end()) {
629         res |= prepCostlyIface(ifn, QuotaShared);
630         if (sharedQuotaIfaces.empty()) {
631             quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes);
632             res |= runIpxtablesCmd(quotaCmd.c_str(), IptJumpReject);
633             if (res) {
634                 ALOGE("Failed set quota rule");
635                 goto fail;
636             }
637             sharedQuotaBytes = maxBytes;
638         }
639         sharedQuotaIfaces.push_front(ifaceName);
640
641     }
642
643     if (maxBytes != sharedQuotaBytes) {
644         res |= updateQuota(costName, maxBytes);
645         if (res) {
646             ALOGE("Failed update quota for %s", costName);
647             goto fail;
648         }
649         sharedQuotaBytes = maxBytes;
650     }
651     return 0;
652
653     fail:
654     /*
655      * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
656      * rules in the kernel to see which ones need cleaning up.
657      * For now callers needs to choose if they want to "ndc bandwidth enable"
658      * which resets everything.
659      */
660     removeInterfaceSharedQuota(ifn);
661     return -1;
662 }
663
664 /* It will also cleanup any shared alerts */
665 int BandwidthController::removeInterfaceSharedQuota(const char *iface) {
666     char ifn[MAX_IFACENAME_LEN];
667     int res = 0;
668     std::string ifaceName;
669     std::list<std::string>::iterator it;
670     const char *costName = "shared";
671
672     if (!isIfaceName(iface))
673         return -1;
674     if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
675         ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
676         return -1;
677     }
678     ifaceName = ifn;
679
680     for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) {
681         if (*it == ifaceName)
682             break;
683     }
684     if (it == sharedQuotaIfaces.end()) {
685         ALOGE("No such iface %s to delete", ifn);
686         return -1;
687     }
688
689     res |= cleanupCostlyIface(ifn, QuotaShared);
690     sharedQuotaIfaces.erase(it);
691
692     if (sharedQuotaIfaces.empty()) {
693         std::string quotaCmd;
694         quotaCmd = makeIptablesQuotaCmd(IptOpDelete, costName, sharedQuotaBytes);
695         res |= runIpxtablesCmd(quotaCmd.c_str(), IptJumpReject);
696         sharedQuotaBytes = 0;
697         if (sharedAlertBytes) {
698             removeSharedAlert();
699             sharedAlertBytes = 0;
700         }
701     }
702     return res;
703 }
704
705 int BandwidthController::setInterfaceQuota(const char *iface, int64_t maxBytes) {
706     char ifn[MAX_IFACENAME_LEN];
707     int res = 0;
708     std::string ifaceName;
709     const char *costName;
710     std::list<QuotaInfo>::iterator it;
711     std::string quotaCmd;
712
713     if (!isIfaceName(iface))
714         return -1;
715
716     if (!maxBytes) {
717         /* Don't talk about -1, deprecate it. */
718         ALOGE("Invalid bytes value. 1..max_int64.");
719         return -1;
720     }
721     if (maxBytes == -1) {
722         return removeInterfaceQuota(iface);
723     }
724
725     if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
726         ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
727         return -1;
728     }
729     ifaceName = ifn;
730     costName = iface;
731
732     /* Insert ingress quota. */
733     for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
734         if (it->ifaceName == ifaceName)
735             break;
736     }
737
738     if (it == quotaIfaces.end()) {
739         /* Preparing the iface adds a penalty/happy box check */
740         res |= prepCostlyIface(ifn, QuotaUnique);
741         /*
742          * The rejecting quota limit should go after the penalty/happy box checks
743          * or else a naughty app could just eat up the quota.
744          * So we append here.
745          */
746         quotaCmd = makeIptablesQuotaCmd(IptOpAppend, costName, maxBytes);
747         res |= runIpxtablesCmd(quotaCmd.c_str(), IptJumpReject);
748         if (res) {
749             ALOGE("Failed set quota rule");
750             goto fail;
751         }
752
753         quotaIfaces.push_front(QuotaInfo(ifaceName, maxBytes, 0));
754
755     } else {
756         res |= updateQuota(costName, maxBytes);
757         if (res) {
758             ALOGE("Failed update quota for %s", iface);
759             goto fail;
760         }
761         it->quota = maxBytes;
762     }
763     return 0;
764
765     fail:
766     /*
767      * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
768      * rules in the kernel to see which ones need cleaning up.
769      * For now callers needs to choose if they want to "ndc bandwidth enable"
770      * which resets everything.
771      */
772     removeInterfaceSharedQuota(ifn);
773     return -1;
774 }
775
776 int BandwidthController::getInterfaceSharedQuota(int64_t *bytes) {
777     return getInterfaceQuota("shared", bytes);
778 }
779
780 int BandwidthController::getInterfaceQuota(const char *costName, int64_t *bytes) {
781     FILE *fp;
782     char *fname;
783     int scanRes;
784
785     if (!isIfaceName(costName))
786         return -1;
787
788     asprintf(&fname, "/proc/net/xt_quota/%s", costName);
789     fp = fopen(fname, "re");
790     free(fname);
791     if (!fp) {
792         ALOGE("Reading quota %s failed (%s)", costName, strerror(errno));
793         return -1;
794     }
795     scanRes = fscanf(fp, "%" SCNd64, bytes);
796     ALOGV("Read quota res=%d bytes=%" PRId64, scanRes, *bytes);
797     fclose(fp);
798     return scanRes == 1 ? 0 : -1;
799 }
800
801 int BandwidthController::removeInterfaceQuota(const char *iface) {
802
803     char ifn[MAX_IFACENAME_LEN];
804     int res = 0;
805     std::string ifaceName;
806     const char *costName;
807     std::list<QuotaInfo>::iterator it;
808
809     if (!isIfaceName(iface))
810         return -1;
811     if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
812         ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
813         return -1;
814     }
815     ifaceName = ifn;
816     costName = iface;
817
818     for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
819         if (it->ifaceName == ifaceName)
820             break;
821     }
822
823     if (it == quotaIfaces.end()) {
824         ALOGE("No such iface %s to delete", ifn);
825         return -1;
826     }
827
828     /* This also removes the quota command of CostlyIface chain. */
829     res |= cleanupCostlyIface(ifn, QuotaUnique);
830
831     quotaIfaces.erase(it);
832
833     return res;
834 }
835
836 int BandwidthController::updateQuota(const char *quotaName, int64_t bytes) {
837     FILE *fp;
838     char *fname;
839
840     if (!isIfaceName(quotaName)) {
841         ALOGE("updateQuota: Invalid quotaName \"%s\"", quotaName);
842         return -1;
843     }
844
845     asprintf(&fname, "/proc/net/xt_quota/%s", quotaName);
846     fp = fopen(fname, "we");
847     free(fname);
848     if (!fp) {
849         ALOGE("Updating quota %s failed (%s)", quotaName, strerror(errno));
850         return -1;
851     }
852     fprintf(fp, "%" PRId64"\n", bytes);
853     fclose(fp);
854     return 0;
855 }
856
857 int BandwidthController::runIptablesAlertCmd(IptOp op, const char *alertName, int64_t bytes) {
858     int res = 0;
859     const char *opFlag;
860     char *alertQuotaCmd;
861
862     switch (op) {
863     case IptOpInsert:
864         opFlag = "-I";
865         break;
866     case IptOpAppend:
867         opFlag = "-A";
868         break;
869     case IptOpReplace:
870         opFlag = "-R";
871         break;
872     default:
873     case IptOpDelete:
874         opFlag = "-D";
875         break;
876     }
877
878     asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_INPUT",
879         bytes, alertName);
880     res |= runIpxtablesCmd(alertQuotaCmd, IptJumpNoAdd);
881     free(alertQuotaCmd);
882     asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_OUTPUT",
883         bytes, alertName);
884     res |= runIpxtablesCmd(alertQuotaCmd, IptJumpNoAdd);
885     free(alertQuotaCmd);
886     return res;
887 }
888
889 int BandwidthController::runIptablesAlertFwdCmd(IptOp op, const char *alertName, int64_t bytes) {
890     int res = 0;
891     const char *opFlag;
892     char *alertQuotaCmd;
893
894     switch (op) {
895     case IptOpInsert:
896         opFlag = "-I";
897         break;
898     case IptOpAppend:
899         opFlag = "-A";
900         break;
901     case IptOpReplace:
902         opFlag = "-R";
903         break;
904     default:
905     case IptOpDelete:
906         opFlag = "-D";
907         break;
908     }
909
910     asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_FORWARD",
911         bytes, alertName);
912     res = runIpxtablesCmd(alertQuotaCmd, IptJumpNoAdd);
913     free(alertQuotaCmd);
914     return res;
915 }
916
917 int BandwidthController::setGlobalAlert(int64_t bytes) {
918     const char *alertName = ALERT_GLOBAL_NAME;
919     int res = 0;
920
921     if (!bytes) {
922         ALOGE("Invalid bytes value. 1..max_int64.");
923         return -1;
924     }
925     if (globalAlertBytes) {
926         res = updateQuota(alertName, bytes);
927     } else {
928         res = runIptablesAlertCmd(IptOpInsert, alertName, bytes);
929         if (globalAlertTetherCount) {
930             ALOGV("setGlobalAlert for %d tether", globalAlertTetherCount);
931             res |= runIptablesAlertFwdCmd(IptOpInsert, alertName, bytes);
932         }
933     }
934     globalAlertBytes = bytes;
935     return res;
936 }
937
938 int BandwidthController::setGlobalAlertInForwardChain(void) {
939     const char *alertName = ALERT_GLOBAL_NAME;
940     int res = 0;
941
942     globalAlertTetherCount++;
943     ALOGV("setGlobalAlertInForwardChain(): %d tether", globalAlertTetherCount);
944
945     /*
946      * If there is no globalAlert active we are done.
947      * If there is an active globalAlert but this is not the 1st
948      * tether, we are also done.
949      */
950     if (!globalAlertBytes || globalAlertTetherCount != 1) {
951         return 0;
952     }
953
954     /* We only add the rule if this was the 1st tether added. */
955     res = runIptablesAlertFwdCmd(IptOpInsert, alertName, globalAlertBytes);
956     return res;
957 }
958
959 int BandwidthController::removeGlobalAlert(void) {
960
961     const char *alertName = ALERT_GLOBAL_NAME;
962     int res = 0;
963
964     if (!globalAlertBytes) {
965         ALOGE("No prior alert set");
966         return -1;
967     }
968     res = runIptablesAlertCmd(IptOpDelete, alertName, globalAlertBytes);
969     if (globalAlertTetherCount) {
970         res |= runIptablesAlertFwdCmd(IptOpDelete, alertName, globalAlertBytes);
971     }
972     globalAlertBytes = 0;
973     return res;
974 }
975
976 int BandwidthController::removeGlobalAlertInForwardChain(void) {
977     int res = 0;
978     const char *alertName = ALERT_GLOBAL_NAME;
979
980     if (!globalAlertTetherCount) {
981         ALOGE("No prior alert set");
982         return -1;
983     }
984
985     globalAlertTetherCount--;
986     /*
987      * If there is no globalAlert active we are done.
988      * If there is an active globalAlert but there are more
989      * tethers, we are also done.
990      */
991     if (!globalAlertBytes || globalAlertTetherCount >= 1) {
992         return 0;
993     }
994
995     /* We only detete the rule if this was the last tether removed. */
996     res = runIptablesAlertFwdCmd(IptOpDelete, alertName, globalAlertBytes);
997     return res;
998 }
999
1000 int BandwidthController::setSharedAlert(int64_t bytes) {
1001     if (!sharedQuotaBytes) {
1002         ALOGE("Need to have a prior shared quota set to set an alert");
1003         return -1;
1004     }
1005     if (!bytes) {
1006         ALOGE("Invalid bytes value. 1..max_int64.");
1007         return -1;
1008     }
1009     return setCostlyAlert("shared", bytes, &sharedAlertBytes);
1010 }
1011
1012 int BandwidthController::removeSharedAlert(void) {
1013     return removeCostlyAlert("shared", &sharedAlertBytes);
1014 }
1015
1016 int BandwidthController::setInterfaceAlert(const char *iface, int64_t bytes) {
1017     std::list<QuotaInfo>::iterator it;
1018
1019     if (!isIfaceName(iface)) {
1020         ALOGE("setInterfaceAlert: Invalid iface \"%s\"", iface);
1021         return -1;
1022     }
1023
1024     if (!bytes) {
1025         ALOGE("Invalid bytes value. 1..max_int64.");
1026         return -1;
1027     }
1028     for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
1029         if (it->ifaceName == iface)
1030             break;
1031     }
1032
1033     if (it == quotaIfaces.end()) {
1034         ALOGE("Need to have a prior interface quota set to set an alert");
1035         return -1;
1036     }
1037
1038     return setCostlyAlert(iface, bytes, &it->alert);
1039 }
1040
1041 int BandwidthController::removeInterfaceAlert(const char *iface) {
1042     std::list<QuotaInfo>::iterator it;
1043
1044     if (!isIfaceName(iface)) {
1045         ALOGE("removeInterfaceAlert: Invalid iface \"%s\"", iface);
1046         return -1;
1047     }
1048
1049     for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
1050         if (it->ifaceName == iface)
1051             break;
1052     }
1053
1054     if (it == quotaIfaces.end()) {
1055         ALOGE("No prior alert set for interface %s", iface);
1056         return -1;
1057     }
1058
1059     return removeCostlyAlert(iface, &it->alert);
1060 }
1061
1062 int BandwidthController::setCostlyAlert(const char *costName, int64_t bytes, int64_t *alertBytes) {
1063     char *alertQuotaCmd;
1064     char *chainName;
1065     int res = 0;
1066     char *alertName;
1067
1068     if (!isIfaceName(costName)) {
1069         ALOGE("setCostlyAlert: Invalid costName \"%s\"", costName);
1070         return -1;
1071     }
1072
1073     if (!bytes) {
1074         ALOGE("Invalid bytes value. 1..max_int64.");
1075         return -1;
1076     }
1077     asprintf(&alertName, "%sAlert", costName);
1078     if (*alertBytes) {
1079         res = updateQuota(alertName, *alertBytes);
1080     } else {
1081         asprintf(&chainName, "bw_costly_%s", costName);
1082         asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "-A", chainName, bytes, alertName);
1083         res |= runIpxtablesCmd(alertQuotaCmd, IptJumpNoAdd);
1084         free(alertQuotaCmd);
1085         free(chainName);
1086     }
1087     *alertBytes = bytes;
1088     free(alertName);
1089     return res;
1090 }
1091
1092 int BandwidthController::removeCostlyAlert(const char *costName, int64_t *alertBytes) {
1093     char *alertQuotaCmd;
1094     char *chainName;
1095     char *alertName;
1096     int res = 0;
1097
1098     if (!isIfaceName(costName)) {
1099         ALOGE("removeCostlyAlert: Invalid costName \"%s\"", costName);
1100         return -1;
1101     }
1102
1103     if (!*alertBytes) {
1104         ALOGE("No prior alert set for %s alert", costName);
1105         return -1;
1106     }
1107
1108     asprintf(&alertName, "%sAlert", costName);
1109     asprintf(&chainName, "bw_costly_%s", costName);
1110     asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "-D", chainName, *alertBytes, alertName);
1111     res |= runIpxtablesCmd(alertQuotaCmd, IptJumpNoAdd);
1112     free(alertQuotaCmd);
1113     free(chainName);
1114
1115     *alertBytes = 0;
1116     free(alertName);
1117     return res;
1118 }
1119
1120 /*
1121  * Parse the ptks and bytes out of:
1122  *   Chain natctrl_tether_counters (4 references)
1123  *       pkts      bytes target     prot opt in     out     source               destination
1124  *         26     2373 RETURN     all  --  wlan0  rmnet0  0.0.0.0/0            0.0.0.0/0
1125  *         27     2002 RETURN     all  --  rmnet0 wlan0   0.0.0.0/0            0.0.0.0/0
1126  *       1040   107471 RETURN     all  --  bt-pan rmnet0  0.0.0.0/0            0.0.0.0/0
1127  *       1450  1708806 RETURN     all  --  rmnet0 bt-pan  0.0.0.0/0            0.0.0.0/0
1128  * It results in an error if invoked and no tethering counter rules exist. The constraint
1129  * helps detect complete parsing failure.
1130  */
1131 int BandwidthController::parseForwardChainStats(SocketClient *cli, const TetherStats filter,
1132                                                 FILE *fp, std::string &extraProcessingInfo) {
1133     int res;
1134     char lineBuffer[MAX_IPT_OUTPUT_LINE_LEN];
1135     char iface0[MAX_IPT_OUTPUT_LINE_LEN];
1136     char iface1[MAX_IPT_OUTPUT_LINE_LEN];
1137     char rest[MAX_IPT_OUTPUT_LINE_LEN];
1138
1139     TetherStats stats;
1140     char *buffPtr;
1141     int64_t packets, bytes;
1142     int statsFound = 0;
1143
1144     bool filterPair = filter.intIface[0] && filter.extIface[0];
1145
1146     char *filterMsg = filter.getStatsLine();
1147     ALOGV("filter: %s",  filterMsg);
1148     free(filterMsg);
1149
1150     stats = filter;
1151
1152     while (NULL != (buffPtr = fgets(lineBuffer, MAX_IPT_OUTPUT_LINE_LEN, fp))) {
1153         /* Clean up, so a failed parse can still print info */
1154         iface0[0] = iface1[0] = rest[0] = packets = bytes = 0;
1155         res = sscanf(buffPtr, "%" SCNd64" %" SCNd64" RETURN all -- %s %s 0.%s",
1156                 &packets, &bytes, iface0, iface1, rest);
1157         ALOGV("parse res=%d iface0=<%s> iface1=<%s> pkts=%" PRId64" bytes=%" PRId64" rest=<%s> orig line=<%s>", res,
1158              iface0, iface1, packets, bytes, rest, buffPtr);
1159         extraProcessingInfo += buffPtr;
1160
1161         if (res != 5) {
1162             continue;
1163         }
1164         /*
1165          * The following assumes that the 1st rule has in:extIface out:intIface,
1166          * which is what NatController sets up.
1167          * If not filtering, the 1st match rx, and sets up the pair for the tx side.
1168          */
1169         if (filter.intIface[0] && filter.extIface[0]) {
1170             if (filter.intIface == iface0 && filter.extIface == iface1) {
1171                 ALOGV("2Filter RX iface_in=%s iface_out=%s rx_bytes=%" PRId64" rx_packets=%" PRId64" ", iface0, iface1, bytes, packets);
1172                 stats.rxPackets = packets;
1173                 stats.rxBytes = bytes;
1174             } else if (filter.intIface == iface1 && filter.extIface == iface0) {
1175                 ALOGV("2Filter TX iface_in=%s iface_out=%s rx_bytes=%" PRId64" rx_packets=%" PRId64" ", iface0, iface1, bytes, packets);
1176                 stats.txPackets = packets;
1177                 stats.txBytes = bytes;
1178             }
1179         } else if (filter.intIface[0] || filter.extIface[0]) {
1180             if (filter.intIface == iface0 || filter.extIface == iface1) {
1181                 ALOGV("1Filter RX iface_in=%s iface_out=%s rx_bytes=%" PRId64" rx_packets=%" PRId64" ", iface0, iface1, bytes, packets);
1182                 stats.intIface = iface0;
1183                 stats.extIface = iface1;
1184                 stats.rxPackets = packets;
1185                 stats.rxBytes = bytes;
1186             } else if (filter.intIface == iface1 || filter.extIface == iface0) {
1187                 ALOGV("1Filter TX iface_in=%s iface_out=%s rx_bytes=%" PRId64" rx_packets=%" PRId64" ", iface0, iface1, bytes, packets);
1188                 stats.intIface = iface1;
1189                 stats.extIface = iface0;
1190                 stats.txPackets = packets;
1191                 stats.txBytes = bytes;
1192             }
1193         } else /* if (!filter.intFace[0] && !filter.extIface[0]) */ {
1194             if (!stats.intIface[0]) {
1195                 ALOGV("0Filter RX iface_in=%s iface_out=%s rx_bytes=%" PRId64" rx_packets=%" PRId64" ", iface0, iface1, bytes, packets);
1196                 stats.intIface = iface0;
1197                 stats.extIface = iface1;
1198                 stats.rxPackets = packets;
1199                 stats.rxBytes = bytes;
1200             } else if (stats.intIface == iface1 && stats.extIface == iface0) {
1201                 ALOGV("0Filter TX iface_in=%s iface_out=%s rx_bytes=%" PRId64" rx_packets=%" PRId64" ", iface0, iface1, bytes, packets);
1202                 stats.txPackets = packets;
1203                 stats.txBytes = bytes;
1204             }
1205         }
1206         if (stats.rxBytes != -1 && stats.txBytes != -1) {
1207             ALOGV("rx_bytes=%" PRId64" tx_bytes=%" PRId64" filterPair=%d", stats.rxBytes, stats.txBytes, filterPair);
1208             /* Send out stats, and prep for the next if needed. */
1209             char *msg = stats.getStatsLine();
1210             if (filterPair) {
1211                 cli->sendMsg(ResponseCode::TetheringStatsResult, msg, false);
1212                 return 0;
1213             } else {
1214                 cli->sendMsg(ResponseCode::TetheringStatsListResult, msg, false);
1215                 stats = filter;
1216             }
1217             free(msg);
1218             statsFound++;
1219         }
1220     }
1221
1222     /* It is always an error to find only one side of the stats. */
1223     /* It is an error to find nothing when not filtering. */
1224     if (((stats.rxBytes == -1) != (stats.txBytes == -1)) ||
1225         (!statsFound && !filterPair)) {
1226         return -1;
1227     }
1228     cli->sendMsg(ResponseCode::CommandOkay, "Tethering stats list completed", false);
1229     return 0;
1230 }
1231
1232 char *BandwidthController::TetherStats::getStatsLine(void) const {
1233     char *msg;
1234     asprintf(&msg, "%s %s %" PRId64" %" PRId64" %" PRId64" %" PRId64, intIface.c_str(), extIface.c_str(),
1235             rxBytes, rxPackets, txBytes, txPackets);
1236     return msg;
1237 }
1238
1239 int BandwidthController::getTetherStats(SocketClient *cli, TetherStats &stats, std::string &extraProcessingInfo) {
1240     int res;
1241     std::string fullCmd;
1242     FILE *iptOutput;
1243
1244     /*
1245      * Why not use some kind of lib to talk to iptables?
1246      * Because the only libs are libiptc and libip6tc in iptables, and they are
1247      * not easy to use. They require the known iptables match modules to be
1248      * preloaded/linked, and require apparently a lot of wrapper code to get
1249      * the wanted info.
1250      */
1251     fullCmd = IPTABLES_PATH;
1252     fullCmd += " -nvx -w -L ";
1253     fullCmd += NatController::LOCAL_TETHER_COUNTERS_CHAIN;
1254     iptOutput = popen(fullCmd.c_str(), "r");
1255     if (!iptOutput) {
1256             ALOGE("Failed to run %s err=%s", fullCmd.c_str(), strerror(errno));
1257             extraProcessingInfo += "Failed to run iptables.";
1258         return -1;
1259     }
1260     res = parseForwardChainStats(cli, stats, iptOutput, extraProcessingInfo);
1261     pclose(iptOutput);
1262
1263     /* Currently NatController doesn't do ipv6 tethering, so we are done. */
1264     return res;
1265 }
1266
1267 void BandwidthController::flushExistingCostlyTables(bool doClean) {
1268     std::string fullCmd;
1269     FILE *iptOutput;
1270
1271     /* Only lookup ip4 table names as ip6 will have the same tables ... */
1272     fullCmd = IPTABLES_PATH;
1273     fullCmd += " -w -S";
1274     iptOutput = popen(fullCmd.c_str(), "r");
1275     if (!iptOutput) {
1276             ALOGE("Failed to run %s err=%s", fullCmd.c_str(), strerror(errno));
1277         return;
1278     }
1279     /* ... then flush/clean both ip4 and ip6 iptables. */
1280     parseAndFlushCostlyTables(iptOutput, doClean);
1281     pclose(iptOutput);
1282 }
1283
1284 void BandwidthController::parseAndFlushCostlyTables(FILE *fp, bool doRemove) {
1285     int res;
1286     char lineBuffer[MAX_IPT_OUTPUT_LINE_LEN];
1287     char costlyIfaceName[MAX_IPT_OUTPUT_LINE_LEN];
1288     char cmd[MAX_CMD_LEN];
1289     char *buffPtr;
1290
1291     while (NULL != (buffPtr = fgets(lineBuffer, MAX_IPT_OUTPUT_LINE_LEN, fp))) {
1292         costlyIfaceName[0] = '\0';   /* So that debugging output always works */
1293         res = sscanf(buffPtr, "-N bw_costly_%s", costlyIfaceName);
1294         ALOGV("parse res=%d costly=<%s> orig line=<%s>", res,
1295             costlyIfaceName, buffPtr);
1296         if (res != 1) {
1297             continue;
1298         }
1299         /* Exclusions: "shared" is not an ifacename */
1300         if (!strcmp(costlyIfaceName, "shared")) {
1301             continue;
1302         }
1303
1304         snprintf(cmd, sizeof(cmd), "-F bw_costly_%s", costlyIfaceName);
1305         runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
1306         if (doRemove) {
1307             snprintf(cmd, sizeof(cmd), "-X bw_costly_%s", costlyIfaceName);
1308             runIpxtablesCmd(cmd, IptJumpNoAdd, IptFailHide);
1309         }
1310     }
1311 }