BandwidthController.cpp revision c4bbfa247dbe4dda17e28694d49afd3ec0b06bad
14a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall/*
24a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * Copyright (C) 2011 The Android Open Source Project
34a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *
44a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * Licensed under the Apache License, Version 2.0 (the "License");
54a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * you may not use this file except in compliance with the License.
64a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * You may obtain a copy of the License at
74a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *
84a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      http://www.apache.org/licenses/LICENSE-2.0
94a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *
104a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * Unless required by applicable law or agreed to in writing, software
114a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * distributed under the License is distributed on an "AS IS" BASIS,
124a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * See the License for the specific language governing permissions and
144a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * limitations under the License.
154a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall */
164a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
17db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall// #define LOG_NDEBUG 0
18db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall
19db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall/*
20db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall * The CommandListener, FrameworkListener don't allow for
21db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall * multiple calls in parallel to reach the BandwidthController.
22db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall * If they ever were to allow it, then netd/ would need some tweaking.
23db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall */
24db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall
258a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall#include <errno.h>
264a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <fcntl.h>
27db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall#include <stdio.h>
288a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall#include <stdlib.h>
294a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <string.h>
304a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
314a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <sys/socket.h>
324a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <sys/stat.h>
334a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <sys/types.h>
344a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <sys/wait.h>
354a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
364a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <linux/netlink.h>
374a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <linux/rtnetlink.h>
384a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <linux/pkt_sched.h>
394a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
404a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#define LOG_TAG "BandwidthController"
414a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <cutils/log.h>
424a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <cutils/properties.h>
434a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
44c4bbfa247dbe4dda17e28694d49afd3ec0b06badGlenn Kastenextern "C" int logwrap(int argc, const char **argv);
459e5e0ce62e88ddf9a09798eda51b0c270d354c8eJP Abgrallextern "C" int system_nosh(const char *command);
464a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
474a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include "BandwidthController.h"
484ab468577647d1ee73810b89d2287eaa5546fecbKazuhiro Ondo#include "oem_iptables_hook.h"
494a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
50db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall/* Alphabetical */
51c2b26cb83d9bf3f91e986625efcc40fc8eb79a13Nick Kralevich#define ALERT_IPT_TEMPLATE "%s %s %s -m quota2 ! --quota %lld --name %s"
52db7da58e8d2aa021060098057f944ef754be06e3JP Abgrallconst int  BandwidthController::ALERT_RULE_POS_IN_COSTLY_CHAIN = 4;
53c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrallconst char BandwidthController::ALERT_GLOBAL_NAME[] = "globalAlert";
54db7da58e8d2aa021060098057f944ef754be06e3JP Abgrallconst char BandwidthController::IP6TABLES_PATH[] = "/system/bin/ip6tables";
55db7da58e8d2aa021060098057f944ef754be06e3JP Abgrallconst char BandwidthController::IPTABLES_PATH[] = "/system/bin/iptables";
56db7da58e8d2aa021060098057f944ef754be06e3JP Abgrallconst int  BandwidthController::MAX_CMD_ARGS = 32;
57db7da58e8d2aa021060098057f944ef754be06e3JP Abgrallconst int  BandwidthController::MAX_CMD_LEN = 1024;
58db7da58e8d2aa021060098057f944ef754be06e3JP Abgrallconst int  BandwidthController::MAX_IFACENAME_LEN = 64;
59db7da58e8d2aa021060098057f944ef754be06e3JP Abgrallconst int  BandwidthController::MAX_IPT_OUTPUT_LINE_LEN = 256;
60db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall
6111b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrallbool BandwidthController::useLogwrapCall = false;
624a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
634a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall/**
644a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * Some comments about the rules:
654a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *  * Ordering
664a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *    - when an interface is marked as costly it should be INSERTED into the INPUT/OUTPUT chains.
674a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      E.g. "-I INPUT -i rmnet0 --goto costly"
684a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *    - quota'd rules in the costly chain should be before penalty_box lookups.
694a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *
704a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * * global quota vs per interface quota
714a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *   - global quota for all costly interfaces uses a single costly chain:
724a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *    . initial rules
73bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall *      iptables -N costly_shared
74bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall *      iptables -I INPUT -i iface0 --goto costly_shared
75bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall *      iptables -I OUTPUT -o iface0 --goto costly_shared
76bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall *      iptables -I costly_shared -m quota \! --quota 500000 \
77bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall *          --jump REJECT --reject-with icmp-net-prohibited
78bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall *      iptables -A costly_shared --jump penalty_box
79bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall *      iptables -A costly_shared -m owner --socket-exists
808a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall *
814a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *    . adding a new iface to this, E.g.:
82bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall *      iptables -I INPUT -i iface1 --goto costly_shared
83bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall *      iptables -I OUTPUT -o iface1 --goto costly_shared
844a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *
854a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *   - quota per interface. This is achieve by having "costly" chains per quota.
864a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *     E.g. adding a new costly interface iface0 with its own quota:
874a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      iptables -N costly_iface0
884a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      iptables -I INPUT -i iface0 --goto costly_iface0
894a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      iptables -I OUTPUT -o iface0 --goto costly_iface0
90bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall *      iptables -A costly_iface0 -m quota \! --quota 500000 \
91bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall *          --jump REJECT --reject-with icmp-net-prohibited
92bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall *      iptables -A costly_iface0 --jump penalty_box
934a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      iptables -A costly_iface0 -m owner --socket-exists
944a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *
954a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * * penalty_box handling:
964a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *  - only one penalty_box for all interfaces
974a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *   E.g  Adding an app:
98bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall *    iptables -A penalty_box -m owner --uid-owner app_3 \
99bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall *        --jump REJECT --reject-with icmp-net-prohibited
1004a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall */
101db7da58e8d2aa021060098057f944ef754be06e3JP Abgrallconst char *BandwidthController::IPT_CLEANUP_COMMANDS[] = {
1020dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    /* Cleanup rules. */
1030dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    "-F",
1040dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    "-t raw -F",
10539f8f24246a5dac21be5cc5e32c0f395ee803766JP Abgrall    /* TODO: If at some point we need more user chains than here, then we will need
10639f8f24246a5dac21be5cc5e32c0f395ee803766JP Abgrall     * a different cleanup approach.
10739f8f24246a5dac21be5cc5e32c0f395ee803766JP Abgrall     */
108bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall    "-X",  /* Should normally only be costly_shared, penalty_box, and costly_<iface>  */
1090dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall};
1104a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
111db7da58e8d2aa021060098057f944ef754be06e3JP Abgrallconst char *BandwidthController::IPT_SETUP_COMMANDS[] = {
1120dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    /* Created needed chains. */
113bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall    "-N costly_shared",
1140dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    "-N penalty_box",
1150dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall};
1160dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
117db7da58e8d2aa021060098057f944ef754be06e3JP Abgrallconst char *BandwidthController::IPT_BASIC_ACCOUNTING_COMMANDS[] = {
1180dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    "-F INPUT",
1190dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    "-A INPUT -i lo --jump ACCEPT",
1200dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    "-A INPUT -m owner --socket-exists", /* This is a tracking rule. */
1210dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
1220dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    "-F OUTPUT",
1230dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    "-A OUTPUT -o lo --jump ACCEPT",
1240dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    "-A OUTPUT -m owner --socket-exists", /* This is a tracking rule. */
1250dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
126bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall    "-F costly_shared",
127bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall    "-A costly_shared --jump penalty_box",
128bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall    "-A costly_shared -m owner --socket-exists", /* This is a tracking rule. */
1290dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    /* TODO(jpa): Figure out why iptables doesn't correctly return from this
1300dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall     * chain. For now, hack the chain exit with an ACCEPT.
1310dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall     */
132bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall    "-A costly_shared --jump ACCEPT",
1330dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall};
1344a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1354a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP AbgrallBandwidthController::BandwidthController(void) {
1364a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    char value[PROPERTY_VALUE_MAX];
1374a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1384a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    property_get("persist.bandwidth.enable", value, "0");
1394a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    if (!strcmp(value, "1")) {
1404a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall        enableBandwidthControl();
1414a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    }
1424a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
14311b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall    property_get("persist.bandwidth.uselogwrap", value, "0");
14411b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall    useLogwrapCall = !strcmp(value, "1");
1454a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall}
1464a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
14726e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrallint BandwidthController::runIpxtablesCmd(const char *cmd, IptRejectOp rejectHandling) {
1480dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    int res = 0;
1498a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
1503fb42e026ffebab2c8f282e42501040121e32d83Steve Block    ALOGV("runIpxtablesCmd(cmd=%s)", cmd);
15126e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    res |= runIptablesCmd(cmd, rejectHandling, IptIpV4);
15226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    res |= runIptablesCmd(cmd, rejectHandling, IptIpV6);
1530dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    return res;
1540dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall}
1550dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
15626e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrallint BandwidthController::StrncpyAndCheck(char *buffer, const char *src, size_t buffSize) {
15726e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall
15826e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    memset(buffer, '\0', buffSize);  // strncpy() is not filling leftover with '\0'
15926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    strncpy(buffer, src, buffSize);
16026e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    return buffer[buffSize - 1];
16126e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall}
16226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall
1638a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrallint BandwidthController::runIptablesCmd(const char *cmd, IptRejectOp rejectHandling,
1648a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall                                        IptIpVer iptVer) {
16526e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    char buffer[MAX_CMD_LEN];
1664a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    const char *argv[MAX_CMD_ARGS];
16726e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    int argc = 0;
1684a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    char *next = buffer;
1694a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    char *tmp;
17011b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall    int res;
1714a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1720dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    std::string fullCmd = cmd;
17326e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall
17426e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    if (rejectHandling == IptRejectAdd) {
1750dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        fullCmd += " --jump REJECT --reject-with";
17626e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        switch (iptVer) {
17726e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        case IptIpV4:
1788a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall            fullCmd += " icmp-net-prohibited";
1798a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall            break;
18026e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        case IptIpV6:
1818a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall            fullCmd += " icmp6-adm-prohibited";
1828a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall            break;
1830dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        }
1840dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    }
1850dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
18611b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall    fullCmd.insert(0, " ");
18711b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall    fullCmd.insert(0, iptVer == IptIpV4 ? IPTABLES_PATH : IP6TABLES_PATH);
1884a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
18911b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall    if (!useLogwrapCall) {
1909e5e0ce62e88ddf9a09798eda51b0c270d354c8eJP Abgrall        res = system_nosh(fullCmd.c_str());
19111b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall    } else {
19211b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall        if (StrncpyAndCheck(buffer, fullCmd.c_str(), sizeof(buffer))) {
1935ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block            ALOGE("iptables command too long");
1944a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            return -1;
1954a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall        }
196fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
19711b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall        argc = 0;
19811b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall        while ((tmp = strsep(&next, " "))) {
19911b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall            argv[argc++] = tmp;
20011b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall            if (argc >= MAX_CMD_ARGS) {
2015ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block                ALOGE("iptables argument overflow");
20211b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall                return -1;
20311b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall            }
20411b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall        }
20511b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall
20611b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall        argv[argc] = NULL;
207c4bbfa247dbe4dda17e28694d49afd3ec0b06badGlenn Kasten        res = logwrap(argc, argv);
20811b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall    }
20911b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall    if (res) {
2105ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block        ALOGE("runIptablesCmd(): failed %s res=%d", fullCmd.c_str(), res);
21111b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall    }
21211b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall    return res;
2134a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall}
2144a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
2154a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallint BandwidthController::enableBandwidthControl(void) {
216fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    int res;
2178a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
218db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall    /* Let's pretend we started from scratch ... */
2198a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    sharedQuotaIfaces.clear();
2208a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    quotaIfaces.clear();
2218a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    naughtyAppUids.clear();
222db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall    globalAlertBytes = 0;
223c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    globalAlertTetherCount = 0;
224db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall    sharedQuotaBytes = sharedAlertBytes = 0;
225db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall
226db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall
227db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall    /* Some of the initialCommands are allowed to fail */
228db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall    runCommands(sizeof(IPT_CLEANUP_COMMANDS) / sizeof(char*),
229db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall            IPT_CLEANUP_COMMANDS, RunCmdFailureOk);
230db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall    runCommands(sizeof(IPT_SETUP_COMMANDS) / sizeof(char*),
231db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall            IPT_SETUP_COMMANDS, RunCmdFailureOk);
232db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall    res = runCommands(sizeof(IPT_BASIC_ACCOUNTING_COMMANDS) / sizeof(char*),
233db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall            IPT_BASIC_ACCOUNTING_COMMANDS, RunCmdFailureBad);
2348a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
2354ab468577647d1ee73810b89d2287eaa5546fecbKazuhiro Ondo    setupOemIptablesHook();
2364ab468577647d1ee73810b89d2287eaa5546fecbKazuhiro Ondo
237fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    return res;
2384a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
2394a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall}
2404a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
2414a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallint BandwidthController::disableBandwidthControl(void) {
242db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall    /* The IPT_CLEANUP_COMMANDS are allowed to fail. */
243db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall    runCommands(sizeof(IPT_CLEANUP_COMMANDS) / sizeof(char*),
244db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall            IPT_CLEANUP_COMMANDS, RunCmdFailureOk);
2454ab468577647d1ee73810b89d2287eaa5546fecbKazuhiro Ondo    setupOemIptablesHook();
246fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    return 0;
2474a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall}
2484a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
2498a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrallint BandwidthController::runCommands(int numCommands, const char *commands[],
2508a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall                                     RunCmdErrHandling cmdErrHandling) {
251fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    int res = 0;
2523fb42e026ffebab2c8f282e42501040121e32d83Steve Block    ALOGV("runCommands(): %d commands", numCommands);
253fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    for (int cmdNum = 0; cmdNum < numCommands; cmdNum++) {
25426e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        res = runIpxtablesCmd(commands[cmdNum], IptRejectNoAdd);
25526e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        if (res && cmdErrHandling != RunCmdFailureBad)
256fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            return res;
257fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    }
25826e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    return cmdErrHandling == RunCmdFailureBad ? res : 0;
259fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall}
260fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
2610dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrallstd::string BandwidthController::makeIptablesNaughtyCmd(IptOp op, int uid) {
262fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    std::string res;
2638a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    char *buff;
2648a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    const char *opFlag;
265fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
266fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    switch (op) {
2678a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    case IptOpInsert:
2688a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        opFlag = "-I";
2698a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        break;
2708a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    case IptOpReplace:
2718a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        opFlag = "-R";
2728a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        break;
2738a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    default:
2748a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    case IptOpDelete:
2758a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        opFlag = "-D";
2768a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        break;
277fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    }
2788a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    asprintf(&buff, "%s penalty_box -m owner --uid-owner %d", opFlag, uid);
2798a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    res = buff;
2808a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    free(buff);
281fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    return res;
282fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall}
283fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
284fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrallint BandwidthController::addNaughtyApps(int numUids, char *appUids[]) {
28526e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    return maninpulateNaughtyApps(numUids, appUids, NaughtyAppOpAdd);
286fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall}
287fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
288fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrallint BandwidthController::removeNaughtyApps(int numUids, char *appUids[]) {
28926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    return maninpulateNaughtyApps(numUids, appUids, NaughtyAppOpRemove);
290fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall}
291fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
29226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrallint BandwidthController::maninpulateNaughtyApps(int numUids, char *appStrUids[], NaughtyAppOp appOp) {
293fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    char cmd[MAX_CMD_LEN];
294fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    int uidNum;
29526e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    const char *failLogTemplate;
29626e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    IptOp op;
297fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    int appUids[numUids];
29826e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    std::string naughtyCmd;
2998a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
30026e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    switch (appOp) {
30126e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    case NaughtyAppOpAdd:
3028a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        op = IptOpInsert;
3038a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        failLogTemplate = "Failed to add app uid %d to penalty box.";
3048a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        break;
30526e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    case NaughtyAppOpRemove:
3068a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        op = IptOpDelete;
3078a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        failLogTemplate = "Failed to delete app uid %d from penalty box.";
3088a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        break;
30926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    }
31026e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall
311fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    for (uidNum = 0; uidNum < numUids; uidNum++) {
312fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        appUids[uidNum] = atol(appStrUids[uidNum]);
313fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        if (appUids[uidNum] == 0) {
3145ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block            ALOGE(failLogTemplate, appUids[uidNum]);
315fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            goto fail_parse;
316fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        }
317fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    }
318fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
319fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    for (uidNum = 0; uidNum < numUids; uidNum++) {
32026e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        naughtyCmd = makeIptablesNaughtyCmd(op, appUids[uidNum]);
32126e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        if (runIpxtablesCmd(naughtyCmd.c_str(), IptRejectAdd)) {
3225ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block            ALOGE(failLogTemplate, appUids[uidNum]);
323fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            goto fail_with_uidNum;
324fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        }
325fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    }
326fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    return 0;
327fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
32826e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrallfail_with_uidNum:
329fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    /* Try to remove the uid that failed in any case*/
33026e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    naughtyCmd = makeIptablesNaughtyCmd(IptOpDelete, appUids[uidNum]);
33126e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    runIpxtablesCmd(naughtyCmd.c_str(), IptRejectAdd);
33226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrallfail_parse:
33326e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    return -1;
3344a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall}
3354a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
33626e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrallstd::string BandwidthController::makeIptablesQuotaCmd(IptOp op, const char *costName, int64_t quota) {
337fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    std::string res;
3388a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    char *buff;
3398a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    const char *opFlag;
3400dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
3413fb42e026ffebab2c8f282e42501040121e32d83Steve Block    ALOGV("makeIptablesQuotaCmd(%d, %lld)", op, quota);
3420dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
343fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    switch (op) {
3448a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    case IptOpInsert:
3458a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        opFlag = "-I";
3468a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        break;
3478a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    case IptOpReplace:
3488a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        opFlag = "-R";
3498a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        break;
3508a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    default:
3518a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    case IptOpDelete:
3528a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        opFlag = "-D";
3538a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        break;
354fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    }
3558a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
356bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall    // The requried IP version specific --jump REJECT ... will be added later.
3578a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    asprintf(&buff, "%s costly_%s -m quota2 ! --quota %lld --name %s", opFlag, costName, quota,
3588a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall             costName);
3598a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    res = buff;
3608a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    free(buff);
3610dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    return res;
3620dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall}
3630dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
36426e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrallint BandwidthController::prepCostlyIface(const char *ifn, QuotaType quotaType) {
3650dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    char cmd[MAX_CMD_LEN];
3660dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    int res = 0;
3678a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    int ruleInsertPos = 1;
3680dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    std::string costString;
3690dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    const char *costCString;
3700dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
3710dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    /* The "-N costly" is created upfront, no need to handle it here. */
37226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    switch (quotaType) {
37326e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    case QuotaUnique:
374bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall        costString = "costly_";
3750dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        costString += ifn;
3760dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        costCString = costString.c_str();
3770dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        snprintf(cmd, sizeof(cmd), "-N %s", costCString);
37826e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
3790dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        snprintf(cmd, sizeof(cmd), "-A %s -j penalty_box", costCString);
38026e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
3810dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        snprintf(cmd, sizeof(cmd), "-A %s -m owner --socket-exists", costCString);
38226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
3830dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        /* TODO(jpa): Figure out why iptables doesn't correctly return from this
3840dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall         * chain. For now, hack the chain exit with an ACCEPT.
3850dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall         */
3860dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        snprintf(cmd, sizeof(cmd), "-A %s --jump ACCEPT", costCString);
38726e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
38826e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        break;
38926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    case QuotaShared:
390bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall        costCString = "costly_shared";
39126e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        break;
3920dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    }
3930dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
3948a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    if (globalAlertBytes) {
3958a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        /* The alert rule comes 1st */
3968a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        ruleInsertPos = 2;
3978a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    }
3988a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    snprintf(cmd, sizeof(cmd), "-I INPUT %d -i %s --goto %s", ruleInsertPos, ifn, costCString);
39926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
4008a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    snprintf(cmd, sizeof(cmd), "-I OUTPUT %d -o %s --goto %s", ruleInsertPos, ifn, costCString);
40126e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
4020dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    return res;
4030dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall}
4040dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
40526e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrallint BandwidthController::cleanupCostlyIface(const char *ifn, QuotaType quotaType) {
4060dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    char cmd[MAX_CMD_LEN];
4070dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    int res = 0;
4080dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    std::string costString;
4090dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    const char *costCString;
4100dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
41126e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    switch (quotaType) {
41226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    case QuotaUnique:
413bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall        costString = "costly_";
4140dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        costString += ifn;
4150dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        costCString = costString.c_str();
41626e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        break;
41726e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    case QuotaShared:
418bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall        costCString = "costly_shared";
41926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        break;
4200dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    }
4210dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
4220dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    snprintf(cmd, sizeof(cmd), "-D INPUT -i %s --goto %s", ifn, costCString);
42326e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
4240dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    snprintf(cmd, sizeof(cmd), "-D OUTPUT -o %s --goto %s", ifn, costCString);
42526e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
4260dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
427bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall    /* The "-N costly_shared" is created upfront, no need to handle it here. */
42826e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    if (quotaType == QuotaUnique) {
4290dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        snprintf(cmd, sizeof(cmd), "-F %s", costCString);
43026e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
431a9f802c23f4c2c53fa1065b75f712ce46f384c3aJP Abgrall        snprintf(cmd, sizeof(cmd), "-X %s", costCString);
432a9f802c23f4c2c53fa1065b75f712ce46f384c3aJP Abgrall        res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
433fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    }
434fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    return res;
435fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall}
4364a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
4370dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrallint BandwidthController::setInterfaceSharedQuota(const char *iface, int64_t maxBytes) {
4384a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    char cmd[MAX_CMD_LEN];
4394a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    char ifn[MAX_IFACENAME_LEN];
440fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    int res = 0;
44126e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    std::string quotaCmd;
4428a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    std::string ifaceName;
4438a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    ;
444bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall    const char *costName = "shared";
44526e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    std::list<std::string>::iterator it;
4464a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
4478a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    if (!maxBytes) {
4488a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        /* Don't talk about -1, deprecate it. */
4495ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block        ALOGE("Invalid bytes value. 1..max_int64.");
4508a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        return -1;
4518a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    }
45226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
4535ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block        ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
45426e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        return -1;
45526e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    }
45626e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    ifaceName = ifn;
4574a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
4584a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    if (maxBytes == -1) {
459fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        return removeInterfaceSharedQuota(ifn);
4604a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    }
4614a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
4624a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    /* Insert ingress quota. */
4630dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) {
4640dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        if (*it == ifaceName)
465fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            break;
4664a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    }
467fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
4680dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    if (it == sharedQuotaIfaces.end()) {
46926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        res |= prepCostlyIface(ifn, QuotaShared);
4700dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        if (sharedQuotaIfaces.empty()) {
4710dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall            quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes);
47226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall            res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd);
4734a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            if (res) {
4745ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block                ALOGE("Failed set quota rule");
475fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall                goto fail;
4764a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            }
477fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            sharedQuotaBytes = maxBytes;
478fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        }
4790dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        sharedQuotaIfaces.push_front(ifaceName);
480fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
481fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    }
482fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
483fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    if (maxBytes != sharedQuotaBytes) {
4848a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        res |= updateQuota(costName, maxBytes);
485fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        if (res) {
4865ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block            ALOGE("Failed update quota for %s", costName);
487fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            goto fail;
488fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        }
489fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        sharedQuotaBytes = maxBytes;
4904a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    }
4914a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    return 0;
492fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
493fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    fail:
4944a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    /*
4954a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall     * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
4964a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall     * rules in the kernel to see which ones need cleaning up.
497fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall     * For now callers needs to choose if they want to "ndc bandwidth enable"
498fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall     * which resets everything.
4994a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall     */
500fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    removeInterfaceSharedQuota(ifn);
5014a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    return -1;
5024a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall}
5034a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
5048a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall/* It will also cleanup any shared alerts */
505fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrallint BandwidthController::removeInterfaceSharedQuota(const char *iface) {
5064a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    char ifn[MAX_IFACENAME_LEN];
507fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    int res = 0;
50826e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    std::string ifaceName;
5090dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    std::list<std::string>::iterator it;
510bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall    const char *costName = "shared";
5114a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
5128a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
5135ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block        ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
51426e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        return -1;
51526e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    }
5168a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    ifaceName = ifn;
51726e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall
5180dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) {
5190dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        if (*it == ifaceName)
520fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            break;
5214a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    }
5220dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    if (it == sharedQuotaIfaces.end()) {
5235ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block        ALOGE("No such iface %s to delete", ifn);
524fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        return -1;
5254a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    }
526fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
52726e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    res |= cleanupCostlyIface(ifn, QuotaShared);
5280dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    sharedQuotaIfaces.erase(it);
529fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
5300dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    if (sharedQuotaIfaces.empty()) {
531fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        std::string quotaCmd;
532bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall        quotaCmd = makeIptablesQuotaCmd(IptOpDelete, costName, sharedQuotaBytes);
53326e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd);
5348a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        sharedQuotaBytes = 0;
5358a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        if (sharedAlertBytes) {
5368a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall            removeSharedAlert();
5378a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall            sharedAlertBytes = 0;
5388a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        }
539fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    }
5404a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    return res;
5414a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall}
5420dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
5430dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrallint BandwidthController::setInterfaceQuota(const char *iface, int64_t maxBytes) {
5440dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    char ifn[MAX_IFACENAME_LEN];
5450dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    int res = 0;
54626e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    std::string ifaceName;
54726e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    const char *costName;
54826e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    std::list<QuotaInfo>::iterator it;
54926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    std::string quotaCmd;
5500dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
5518a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    if (!maxBytes) {
5528a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        /* Don't talk about -1, deprecate it. */
5535ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block        ALOGE("Invalid bytes value. 1..max_int64.");
5548a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        return -1;
5558a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    }
5560dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    if (maxBytes == -1) {
55726e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        return removeInterfaceQuota(iface);
5580dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    }
5590dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
5608a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
5615ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block        ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
56226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        return -1;
56326e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    }
56426e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    ifaceName = ifn;
56526e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    costName = iface;
56626e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall
5670dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    /* Insert ingress quota. */
5680dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
5698a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        if (it->ifaceName == ifaceName)
5700dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall            break;
5710dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    }
5720dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
5730dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    if (it == quotaIfaces.end()) {
57426e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        res |= prepCostlyIface(ifn, QuotaUnique);
5750dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes);
57626e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd);
5770dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        if (res) {
5785ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block            ALOGE("Failed set quota rule");
5790dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall            goto fail;
5800dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        }
5810dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
5828a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        quotaIfaces.push_front(QuotaInfo(ifaceName, maxBytes, 0));
5830dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
5840dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    } else {
5858a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        res |= updateQuota(costName, maxBytes);
5860dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        if (res) {
5875ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block            ALOGE("Failed update quota for %s", iface);
5880dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall            goto fail;
5890dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        }
5908a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        it->quota = maxBytes;
5910dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    }
5920dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    return 0;
5930dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
5940dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    fail:
5950dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    /*
5960dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall     * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
5970dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall     * rules in the kernel to see which ones need cleaning up.
5980dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall     * For now callers needs to choose if they want to "ndc bandwidth enable"
5990dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall     * which resets everything.
6000dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall     */
6010dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    removeInterfaceSharedQuota(ifn);
6020dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    return -1;
6030dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall}
6040dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
6058a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrallint BandwidthController::getInterfaceSharedQuota(int64_t *bytes) {
6068a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    return getInterfaceQuota("shared", bytes);
6078a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall}
6088a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
6098a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrallint BandwidthController::getInterfaceQuota(const char *costName, int64_t *bytes) {
6108a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    FILE *fp;
6118a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    char *fname;
6128a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    int scanRes;
6138a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
6148a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    asprintf(&fname, "/proc/net/xt_quota/%s", costName);
6158a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    fp = fopen(fname, "r");
6168a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    free(fname);
6178a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    if (!fp) {
6185ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block        ALOGE("Reading quota %s failed (%s)", costName, strerror(errno));
6198a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        return -1;
6208a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    }
6218a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    scanRes = fscanf(fp, "%lld", bytes);
6223fb42e026ffebab2c8f282e42501040121e32d83Steve Block    ALOGV("Read quota res=%d bytes=%lld", scanRes, *bytes);
6238a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    fclose(fp);
6248a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    return scanRes == 1 ? 0 : -1;
6258a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall}
6268a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
6270dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrallint BandwidthController::removeInterfaceQuota(const char *iface) {
6280dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
6290dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    char ifn[MAX_IFACENAME_LEN];
6300dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    int res = 0;
63126e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    std::string ifaceName;
63226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    const char *costName;
63326e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    std::list<QuotaInfo>::iterator it;
6340dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
6358a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
6365ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block        ALOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
63726e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        return -1;
63826e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    }
63926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    ifaceName = ifn;
64026e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    costName = iface;
6410dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
6420dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
6438a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        if (it->ifaceName == ifaceName)
6440dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall            break;
6450dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    }
6460dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
6470dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    if (it == quotaIfaces.end()) {
6485ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block        ALOGE("No such iface %s to delete", ifn);
6490dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        return -1;
6500dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    }
6510dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
6520dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    /* This also removes the quota command of CostlyIface chain. */
65326e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    res |= cleanupCostlyIface(ifn, QuotaUnique);
6540dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
6550dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    quotaIfaces.erase(it);
6560dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
6570dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    return res;
6580dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall}
6598a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
6608a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrallint BandwidthController::updateQuota(const char *quotaName, int64_t bytes) {
6618a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    FILE *fp;
6628a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    char *fname;
6638a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
6648a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    asprintf(&fname, "/proc/net/xt_quota/%s", quotaName);
6658a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    fp = fopen(fname, "w");
6668a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    free(fname);
6678a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    if (!fp) {
6685ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block        ALOGE("Updating quota %s failed (%s)", quotaName, strerror(errno));
6698a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        return -1;
6708a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    }
6718a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    fprintf(fp, "%lld\n", bytes);
6728a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    fclose(fp);
6738a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    return 0;
6748a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall}
6758a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
6768a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrallint BandwidthController::runIptablesAlertCmd(IptOp op, const char *alertName, int64_t bytes) {
6778a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    int res = 0;
6788a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    const char *opFlag;
679876666947664c718a8d0cae9bbddb06cc91f912cJP Abgrall    const char *ifaceLimiting;
6808a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    char *alertQuotaCmd;
6818a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
6828a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    switch (op) {
6838a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    case IptOpInsert:
6848a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        opFlag = "-I";
6858a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        break;
6868a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    case IptOpReplace:
6878a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        opFlag = "-R";
6888a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        break;
6898a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    default:
6908a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    case IptOpDelete:
6918a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        opFlag = "-D";
6928a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        break;
6938a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    }
6948a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
695876666947664c718a8d0cae9bbddb06cc91f912cJP Abgrall    ifaceLimiting = "! -i lo+";
696876666947664c718a8d0cae9bbddb06cc91f912cJP Abgrall    asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, ifaceLimiting, opFlag, "INPUT",
697c2b26cb83d9bf3f91e986625efcc40fc8eb79a13Nick Kralevich        bytes, alertName);
6988a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
6998a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    free(alertQuotaCmd);
700876666947664c718a8d0cae9bbddb06cc91f912cJP Abgrall    ifaceLimiting = "! -o lo+";
701876666947664c718a8d0cae9bbddb06cc91f912cJP Abgrall    asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, ifaceLimiting, opFlag, "OUTPUT",
702c2b26cb83d9bf3f91e986625efcc40fc8eb79a13Nick Kralevich        bytes, alertName);
7038a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
7048a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    free(alertQuotaCmd);
7058a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    return res;
7068a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall}
7078a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
708c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrallint BandwidthController::runIptablesAlertFwdCmd(IptOp op, const char *alertName, int64_t bytes) {
709c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    int res = 0;
710c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    const char *opFlag;
711c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    const char *ifaceLimiting;
7128a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    char *alertQuotaCmd;
713c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall
714c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    switch (op) {
715c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    case IptOpInsert:
716c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall        opFlag = "-I";
717c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall        break;
718c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    case IptOpReplace:
719c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall        opFlag = "-R";
720c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall        break;
721c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    default:
722c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    case IptOpDelete:
723c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall        opFlag = "-D";
724c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall        break;
725c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    }
726c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall
727c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    ifaceLimiting = "! -i lo+";
728c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, ifaceLimiting, opFlag, "FORWARD",
729c2b26cb83d9bf3f91e986625efcc40fc8eb79a13Nick Kralevich        bytes, alertName);
730c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    res = runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
731c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    free(alertQuotaCmd);
732c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    return res;
733c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall}
734c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall
735c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrallint BandwidthController::setGlobalAlert(int64_t bytes) {
736c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    const char *alertName = ALERT_GLOBAL_NAME;
7378a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    int res = 0;
7388a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
7398a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    if (!bytes) {
7405ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block        ALOGE("Invalid bytes value. 1..max_int64.");
7418a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        return -1;
7428a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    }
7438a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    if (globalAlertBytes) {
7448a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        res = updateQuota(alertName, bytes);
7458a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    } else {
7468a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        res = runIptablesAlertCmd(IptOpInsert, alertName, bytes);
747c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall        if (globalAlertTetherCount) {
7483fb42e026ffebab2c8f282e42501040121e32d83Steve Block            ALOGV("setGlobalAlert for %d tether", globalAlertTetherCount);
749c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall            res |= runIptablesAlertFwdCmd(IptOpInsert, alertName, bytes);
750c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall        }
7518a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    }
7528a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    globalAlertBytes = bytes;
7538a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    return res;
7548a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall}
7558a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
756c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrallint BandwidthController::setGlobalAlertInForwardChain(void) {
757c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    const char *alertName = ALERT_GLOBAL_NAME;
758c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    int res = 0;
759c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall
760c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    globalAlertTetherCount++;
7613fb42e026ffebab2c8f282e42501040121e32d83Steve Block    ALOGV("setGlobalAlertInForwardChain(): %d tether", globalAlertTetherCount);
762c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall
763c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    /*
764c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall     * If there is no globalAlert active we are done.
765c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall     * If there is an active globalAlert but this is not the 1st
766c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall     * tether, we are also done.
767c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall     */
768c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    if (!globalAlertBytes || globalAlertTetherCount != 1) {
769c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall        return 0;
770c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    }
771c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall
772c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    /* We only add the rule if this was the 1st tether added. */
773c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    res = runIptablesAlertFwdCmd(IptOpInsert, alertName, globalAlertBytes);
774c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    return res;
775c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall}
776c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall
7778a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrallint BandwidthController::removeGlobalAlert(void) {
7788a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
779c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    const char *alertName = ALERT_GLOBAL_NAME;
7808a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    int res = 0;
7818a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
7828a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    if (!globalAlertBytes) {
7835ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block        ALOGE("No prior alert set");
7848a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        return -1;
7858a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    }
7868a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    res = runIptablesAlertCmd(IptOpDelete, alertName, globalAlertBytes);
787c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    if (globalAlertTetherCount) {
788c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall        res |= runIptablesAlertFwdCmd(IptOpDelete, alertName, globalAlertBytes);
789c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    }
7908a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    globalAlertBytes = 0;
7918a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    return res;
7928a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall}
7938a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
794c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrallint BandwidthController::removeGlobalAlertInForwardChain(void) {
795c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    int res = 0;
796c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    const char *alertName = ALERT_GLOBAL_NAME;
797c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall
798c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    if (!globalAlertTetherCount) {
7995ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block        ALOGE("No prior alert set");
800c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall        return -1;
801c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    }
802c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall
803c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    globalAlertTetherCount--;
804c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    /*
805c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall     * If there is no globalAlert active we are done.
806c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall     * If there is an active globalAlert but there are more
807c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall     * tethers, we are also done.
808c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall     */
809c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    if (!globalAlertBytes || globalAlertTetherCount >= 1) {
810c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall        return 0;
811c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    }
812c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall
813c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    /* We only detete the rule if this was the last tether removed. */
814c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    res = runIptablesAlertFwdCmd(IptOpDelete, alertName, globalAlertBytes);
815c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall    return res;
816c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall}
817c6c673496184bed6d62cf92a6fc7ed43fd94acd5JP Abgrall
8188a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrallint BandwidthController::setSharedAlert(int64_t bytes) {
8198a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    if (!sharedQuotaBytes) {
8205ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block        ALOGE("Need to have a prior shared quota set to set an alert");
8218a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        return -1;
8228a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    }
8238a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    if (!bytes) {
8245ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block        ALOGE("Invalid bytes value. 1..max_int64.");
8258a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        return -1;
8268a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    }
8278a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    return setCostlyAlert("shared", bytes, &sharedAlertBytes);
8288a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall}
8298a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
8308a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrallint BandwidthController::removeSharedAlert(void) {
8318a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    return removeCostlyAlert("shared", &sharedAlertBytes);
8328a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall}
8338a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
8348a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrallint BandwidthController::setInterfaceAlert(const char *iface, int64_t bytes) {
8358a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    std::list<QuotaInfo>::iterator it;
8368a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
8378a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    if (!bytes) {
8385ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block        ALOGE("Invalid bytes value. 1..max_int64.");
8398a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        return -1;
8408a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    }
8418a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
8428a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        if (it->ifaceName == iface)
8438a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall            break;
8448a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    }
8458a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
8468a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    if (it == quotaIfaces.end()) {
8475ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block        ALOGE("Need to have a prior interface quota set to set an alert");
8488a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        return -1;
8498a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    }
8508a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
8518a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    return setCostlyAlert(iface, bytes, &it->alert);
8528a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall}
8538a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
8548a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrallint BandwidthController::removeInterfaceAlert(const char *iface) {
8558a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    std::list<QuotaInfo>::iterator it;
8568a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
8578a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
8588a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        if (it->ifaceName == iface)
8598a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall            break;
8608a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    }
8618a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
8628a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    if (it == quotaIfaces.end()) {
8635ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block        ALOGE("No prior alert set for interface %s", iface);
8648a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        return -1;
8658a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    }
8668a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
8678a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    return removeCostlyAlert(iface, &it->alert);
8688a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall}
8698a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
8708a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrallint BandwidthController::setCostlyAlert(const char *costName, int64_t bytes, int64_t *alertBytes) {
8718a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    char *alertQuotaCmd;
8728a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    char *chainNameAndPos;
8738a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    int res = 0;
8748a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    char *alertName;
8758a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
8768a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    if (!bytes) {
8775ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block        ALOGE("Invalid bytes value. 1..max_int64.");
8788a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        return -1;
8798a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    }
8808a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    asprintf(&alertName, "%sAlert", costName);
8818a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    if (*alertBytes) {
8828a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        res = updateQuota(alertName, *alertBytes);
8838a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    } else {
8848a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        asprintf(&chainNameAndPos, "costly_%s %d", costName, ALERT_RULE_POS_IN_COSTLY_CHAIN);
885c2b26cb83d9bf3f91e986625efcc40fc8eb79a13Nick Kralevich        asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "", "-I", chainNameAndPos, bytes, alertName);
8868a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
8878a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        free(alertQuotaCmd);
8888a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        free(chainNameAndPos);
8898a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    }
8908a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    *alertBytes = bytes;
8918a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    free(alertName);
8928a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    return res;
8938a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall}
8948a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
8958a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrallint BandwidthController::removeCostlyAlert(const char *costName, int64_t *alertBytes) {
8968a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    char *alertQuotaCmd;
8978a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    char *chainName;
8988a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    char *alertName;
8998a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    int res = 0;
9008a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
9018a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    asprintf(&alertName, "%sAlert", costName);
9028a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    if (!*alertBytes) {
9035ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block        ALOGE("No prior alert set for %s alert", costName);
9048a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        return -1;
9058a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    }
9068a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
9078a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    asprintf(&chainName, "costly_%s", costName);
908c2b26cb83d9bf3f91e986625efcc40fc8eb79a13Nick Kralevich    asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "", "-D", chainName, *alertBytes, alertName);
9098a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
9108a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    free(alertQuotaCmd);
9118a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    free(chainName);
9128a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
9138a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    *alertBytes = 0;
9148a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    free(alertName);
9158a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    return res;
9168a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall}
917db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall
918db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall/*
919db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall * Parse the ptks and bytes out of:
920db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall * Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
921db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall *     pkts      bytes target     prot opt in     out     source               destination
922db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall *        0        0 ACCEPT     all  --  rmnet0 wlan0   0.0.0.0/0            0.0.0.0/0            state RELATED,ESTABLISHED
923db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall *        0        0 DROP       all  --  wlan0  rmnet0  0.0.0.0/0            0.0.0.0/0            state INVALID
924db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall *        0        0 ACCEPT     all  --  wlan0  rmnet0  0.0.0.0/0            0.0.0.0/0
925db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall *
926db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall */
927a2a64f004f1677daf16b0b03d589d6572ec547c2JP Abgrallint BandwidthController::parseForwardChainStats(TetherStats &stats, FILE *fp,
928a2a64f004f1677daf16b0b03d589d6572ec547c2JP Abgrall                                                std::string &extraProcessingInfo) {
929db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall    int res;
930db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall    char lineBuffer[MAX_IPT_OUTPUT_LINE_LEN];
931db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall    char iface0[MAX_IPT_OUTPUT_LINE_LEN];
932db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall    char iface1[MAX_IPT_OUTPUT_LINE_LEN];
933db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall    char rest[MAX_IPT_OUTPUT_LINE_LEN];
934db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall
935db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall    char *buffPtr;
936db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall    int64_t packets, bytes;
937db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall
938db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall    while (NULL != (buffPtr = fgets(lineBuffer, MAX_IPT_OUTPUT_LINE_LEN, fp))) {
939db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall        /* Clean up, so a failed parse can still print info */
940db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall        iface0[0] = iface1[0] = rest[0] = packets = bytes = 0;
941db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall        res = sscanf(buffPtr, "%lld %lld ACCEPT all -- %s %s 0.%s",
942db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall                &packets, &bytes, iface0, iface1, rest);
9433fb42e026ffebab2c8f282e42501040121e32d83Steve Block        ALOGV("parse res=%d iface0=<%s> iface1=<%s> pkts=%lld bytes=%lld rest=<%s> orig line=<%s>", res,
944db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall             iface0, iface1, packets, bytes, rest, buffPtr);
945a2a64f004f1677daf16b0b03d589d6572ec547c2JP Abgrall        extraProcessingInfo += buffPtr;
946a2a64f004f1677daf16b0b03d589d6572ec547c2JP Abgrall
947db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall        if (res != 5) {
948db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall            continue;
949db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall        }
950db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall        if ((stats.ifaceIn == iface0) && (stats.ifaceOut == iface1)) {
9513fb42e026ffebab2c8f282e42501040121e32d83Steve Block            ALOGV("iface_in=%s iface_out=%s rx_bytes=%lld rx_packets=%lld ", iface0, iface1, bytes, packets);
952db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall            stats.rxPackets = packets;
953db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall            stats.rxBytes = bytes;
954db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall        } else if ((stats.ifaceOut == iface0) && (stats.ifaceIn == iface1)) {
9553fb42e026ffebab2c8f282e42501040121e32d83Steve Block            ALOGV("iface_in=%s iface_out=%s tx_bytes=%lld tx_packets=%lld ", iface1, iface0, bytes, packets);
956db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall            stats.txPackets = packets;
957db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall            stats.txBytes = bytes;
958db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall        }
959db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall    }
960db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall    /* Failure if rx or tx was not found */
961db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall    return (stats.rxBytes == -1 || stats.txBytes == -1) ? -1 : 0;
962db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall}
963db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall
964db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall
965db7da58e8d2aa021060098057f944ef754be06e3JP Abgrallchar *BandwidthController::TetherStats::getStatsLine(void) {
966db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall    char *msg;
967db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall    asprintf(&msg, "%s %s %lld %lld %lld %lld", ifaceIn.c_str(), ifaceOut.c_str(),
968db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall            rxBytes, rxPackets, txBytes, txPackets);
969db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall    return msg;
970db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall}
971db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall
972a2a64f004f1677daf16b0b03d589d6572ec547c2JP Abgrallint BandwidthController::getTetherStats(TetherStats &stats, std::string &extraProcessingInfo) {
973db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall    int res;
974db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall    std::string fullCmd;
975db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall    FILE *iptOutput;
976db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall    const char *cmd;
977db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall
978db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall    if (stats.rxBytes != -1 || stats.txBytes != -1) {
9795ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block        ALOGE("Unexpected input stats. Byte counts should be -1.");
980db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall        return -1;
981db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall    }
982db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall
983db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall    /*
984db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall     * Why not use some kind of lib to talk to iptables?
985db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall     * Because the only libs are libiptc and libip6tc in iptables, and they are
986db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall     * not easy to use. They require the known iptables match modules to be
987db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall     * preloaded/linked, and require apparently a lot of wrapper code to get
988db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall     * the wanted info.
989db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall     */
990db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall    fullCmd = IPTABLES_PATH;
991db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall    fullCmd += " -nvx -L FORWARD";
992db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall    iptOutput = popen(fullCmd.c_str(), "r");
993db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall    if (!iptOutput) {
9945ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block            ALOGE("Failed to run %s err=%s", fullCmd.c_str(), strerror(errno));
995a2a64f004f1677daf16b0b03d589d6572ec547c2JP Abgrall            extraProcessingInfo += "Failed to run iptables.";
996db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall        return -1;
997db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall    }
998a2a64f004f1677daf16b0b03d589d6572ec547c2JP Abgrall    res = parseForwardChainStats(stats, iptOutput, extraProcessingInfo);
999db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall    pclose(iptOutput);
1000db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall
1001db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall    /* Currently NatController doesn't do ipv6 tethering, so we are done. */
1002db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall    return res;
1003db7da58e8d2aa021060098057f944ef754be06e3JP Abgrall}
1004