Home | History | Annotate | Download | only in server
      1 /*
      2  * Copyright (C) 2008 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 #include <stdlib.h>
     20 #include <sys/socket.h>
     21 #include <sys/types.h>
     22 #include <netinet/in.h>
     23 #include <arpa/inet.h>
     24 #include <dirent.h>
     25 #include <errno.h>
     26 #include <string.h>
     27 #include <linux/if.h>
     28 #include <resolv_netid.h>
     29 #include <resolv_params.h>
     30 
     31 #define __STDC_FORMAT_MACROS 1
     32 #include <inttypes.h>
     33 
     34 #define LOG_TAG "CommandListener"
     35 
     36 #include <cutils/log.h>
     37 #include <netutils/ifc.h>
     38 #include <sysutils/SocketClient.h>
     39 
     40 #include "Controllers.h"
     41 #include "CommandListener.h"
     42 #include "ResponseCode.h"
     43 #include "BandwidthController.h"
     44 #include "IdletimerController.h"
     45 #include "oem_iptables_hook.h"
     46 #include "NetdConstants.h"
     47 #include "FirewallController.h"
     48 #include "RouteController.h"
     49 #include "UidRanges.h"
     50 
     51 #include <string>
     52 #include <vector>
     53 
     54 using android::net::gCtls;
     55 
     56 namespace {
     57 
     58 const unsigned NUM_OEM_IDS = NetworkController::MAX_OEM_ID - NetworkController::MIN_OEM_ID + 1;
     59 
     60 Permission stringToPermission(const char* arg) {
     61     if (!strcmp(arg, "NETWORK")) {
     62         return PERMISSION_NETWORK;
     63     }
     64     if (!strcmp(arg, "SYSTEM")) {
     65         return PERMISSION_SYSTEM;
     66     }
     67     return PERMISSION_NONE;
     68 }
     69 
     70 unsigned stringToNetId(const char* arg) {
     71     if (!strcmp(arg, "local")) {
     72         return NetworkController::LOCAL_NET_ID;
     73     }
     74     // OEM NetIds are "oem1", "oem2", .., "oem50".
     75     if (!strncmp(arg, "oem", 3)) {
     76         unsigned n = strtoul(arg + 3, NULL, 0);
     77         if (1 <= n && n <= NUM_OEM_IDS) {
     78             return NetworkController::MIN_OEM_ID + n;
     79         }
     80         return NETID_UNSET;
     81     }
     82     // strtoul() returns 0 on errors, which is fine because 0 is an invalid netId.
     83     return strtoul(arg, NULL, 0);
     84 }
     85 
     86 class LockingFrameworkCommand : public FrameworkCommand {
     87 public:
     88     LockingFrameworkCommand(FrameworkCommand *wrappedCmd, android::RWLock& lock) :
     89             FrameworkCommand(wrappedCmd->getCommand()),
     90             mWrappedCmd(wrappedCmd),
     91             mLock(lock) {}
     92 
     93     int runCommand(SocketClient *c, int argc, char **argv) {
     94         android::RWLock::AutoWLock lock(mLock);
     95         return mWrappedCmd->runCommand(c, argc, argv);
     96     }
     97 
     98 private:
     99     FrameworkCommand *mWrappedCmd;
    100     android::RWLock& mLock;
    101 };
    102 
    103 
    104 }  // namespace
    105 
    106 /**
    107  * List of module chains to be created, along with explicit ordering. ORDERING
    108  * IS CRITICAL, AND SHOULD BE TRIPLE-CHECKED WITH EACH CHANGE.
    109  */
    110 static const char* FILTER_INPUT[] = {
    111         // Bandwidth should always be early in input chain, to make sure we
    112         // correctly count incoming traffic against data plan.
    113         BandwidthController::LOCAL_INPUT,
    114         FirewallController::LOCAL_INPUT,
    115         NULL,
    116 };
    117 
    118 static const char* FILTER_FORWARD[] = {
    119         OEM_IPTABLES_FILTER_FORWARD,
    120         FirewallController::LOCAL_FORWARD,
    121         BandwidthController::LOCAL_FORWARD,
    122         NatController::LOCAL_FORWARD,
    123         NULL,
    124 };
    125 
    126 static const char* FILTER_OUTPUT[] = {
    127         OEM_IPTABLES_FILTER_OUTPUT,
    128         FirewallController::LOCAL_OUTPUT,
    129         StrictController::LOCAL_OUTPUT,
    130         BandwidthController::LOCAL_OUTPUT,
    131         NULL,
    132 };
    133 
    134 static const char* RAW_PREROUTING[] = {
    135         BandwidthController::LOCAL_RAW_PREROUTING,
    136         IdletimerController::LOCAL_RAW_PREROUTING,
    137         NULL,
    138 };
    139 
    140 static const char* MANGLE_POSTROUTING[] = {
    141         BandwidthController::LOCAL_MANGLE_POSTROUTING,
    142         IdletimerController::LOCAL_MANGLE_POSTROUTING,
    143         NULL,
    144 };
    145 
    146 static const char* MANGLE_FORWARD[] = {
    147         NatController::LOCAL_MANGLE_FORWARD,
    148         NULL,
    149 };
    150 
    151 static const char* NAT_PREROUTING[] = {
    152         OEM_IPTABLES_NAT_PREROUTING,
    153         NULL,
    154 };
    155 
    156 static const char* NAT_POSTROUTING[] = {
    157         NatController::LOCAL_NAT_POSTROUTING,
    158         NULL,
    159 };
    160 
    161 static void createChildChains(IptablesTarget target, const char* table, const char* parentChain,
    162         const char** childChains) {
    163     const char** childChain = childChains;
    164     do {
    165         // Order is important:
    166         // -D to delete any pre-existing jump rule (removes references
    167         //    that would prevent -X from working)
    168         // -F to flush any existing chain
    169         // -X to delete any existing chain
    170         // -N to create the chain
    171         // -A to append the chain to parent
    172 
    173         execIptablesSilently(target, "-t", table, "-D", parentChain, "-j", *childChain, NULL);
    174         execIptablesSilently(target, "-t", table, "-F", *childChain, NULL);
    175         execIptablesSilently(target, "-t", table, "-X", *childChain, NULL);
    176         execIptables(target, "-t", table, "-N", *childChain, NULL);
    177         execIptables(target, "-t", table, "-A", parentChain, "-j", *childChain, NULL);
    178     } while (*(++childChain) != NULL);
    179 }
    180 
    181 void CommandListener::registerLockingCmd(FrameworkCommand *cmd, android::RWLock& lock) {
    182     registerCmd(new LockingFrameworkCommand(cmd, lock));
    183 }
    184 
    185 CommandListener::CommandListener() :
    186                  FrameworkListener("netd", true) {
    187     registerLockingCmd(new InterfaceCmd());
    188     registerLockingCmd(new IpFwdCmd());
    189     registerLockingCmd(new TetherCmd());
    190     registerLockingCmd(new NatCmd());
    191     registerLockingCmd(new ListTtysCmd());
    192     registerLockingCmd(new PppdCmd());
    193     registerLockingCmd(new SoftapCmd());
    194     registerLockingCmd(new BandwidthControlCmd(), gCtls->bandwidthCtrl.lock);
    195     registerLockingCmd(new IdletimerControlCmd());
    196     registerLockingCmd(new ResolverCmd());
    197     registerLockingCmd(new FirewallCmd(), gCtls->firewallCtrl.lock);
    198     registerLockingCmd(new ClatdCmd());
    199     registerLockingCmd(new NetworkCommand());
    200     registerLockingCmd(new StrictCmd());
    201 
    202     /*
    203      * This is the only time we touch top-level chains in iptables; controllers
    204      * should only mutate rules inside of their children chains, as created by
    205      * the constants above.
    206      *
    207      * Modules should never ACCEPT packets (except in well-justified cases);
    208      * they should instead defer to any remaining modules using RETURN, or
    209      * otherwise DROP/REJECT.
    210      */
    211 
    212     // Create chains for children modules
    213     createChildChains(V4V6, "filter", "INPUT", FILTER_INPUT);
    214     createChildChains(V4V6, "filter", "FORWARD", FILTER_FORWARD);
    215     createChildChains(V4V6, "filter", "OUTPUT", FILTER_OUTPUT);
    216     createChildChains(V4V6, "raw", "PREROUTING", RAW_PREROUTING);
    217     createChildChains(V4V6, "mangle", "POSTROUTING", MANGLE_POSTROUTING);
    218     createChildChains(V4, "mangle", "FORWARD", MANGLE_FORWARD);
    219     createChildChains(V4, "nat", "PREROUTING", NAT_PREROUTING);
    220     createChildChains(V4, "nat", "POSTROUTING", NAT_POSTROUTING);
    221 
    222     // Let each module setup their child chains
    223     setupOemIptablesHook();
    224 
    225     /* When enabled, DROPs all packets except those matching rules. */
    226     gCtls->firewallCtrl.setupIptablesHooks();
    227 
    228     /* Does DROPs in FORWARD by default */
    229     gCtls->natCtrl.setupIptablesHooks();
    230     /*
    231      * Does REJECT in INPUT, OUTPUT. Does counting also.
    232      * No DROP/REJECT allowed later in netfilter-flow hook order.
    233      */
    234     gCtls->bandwidthCtrl.setupIptablesHooks();
    235     /*
    236      * Counts in nat: PREROUTING, POSTROUTING.
    237      * No DROP/REJECT allowed later in netfilter-flow hook order.
    238      */
    239     gCtls->idletimerCtrl.setupIptablesHooks();
    240 
    241     gCtls->bandwidthCtrl.enableBandwidthControl(false);
    242 
    243     if (int ret = RouteController::Init(NetworkController::LOCAL_NET_ID)) {
    244         ALOGE("failed to initialize RouteController (%s)", strerror(-ret));
    245     }
    246 }
    247 
    248 CommandListener::InterfaceCmd::InterfaceCmd() :
    249                  NetdCommand("interface") {
    250 }
    251 
    252 int CommandListener::InterfaceCmd::runCommand(SocketClient *cli,
    253                                                       int argc, char **argv) {
    254     if (argc < 2) {
    255         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
    256         return 0;
    257     }
    258 
    259     if (!strcmp(argv[1], "list")) {
    260         DIR *d;
    261         struct dirent *de;
    262 
    263         if (!(d = opendir("/sys/class/net"))) {
    264             cli->sendMsg(ResponseCode::OperationFailed, "Failed to open sysfs dir", true);
    265             return 0;
    266         }
    267 
    268         while((de = readdir(d))) {
    269             if (de->d_name[0] == '.')
    270                 continue;
    271             cli->sendMsg(ResponseCode::InterfaceListResult, de->d_name, false);
    272         }
    273         closedir(d);
    274         cli->sendMsg(ResponseCode::CommandOkay, "Interface list completed", false);
    275         return 0;
    276     } else {
    277         /*
    278          * These commands take a minimum of 3 arguments
    279          */
    280         if (argc < 3) {
    281             cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
    282             return 0;
    283         }
    284 
    285         if (!strcmp(argv[1], "getcfg")) {
    286             struct in_addr addr;
    287             int prefixLength;
    288             unsigned char hwaddr[6];
    289             unsigned flags = 0;
    290 
    291             ifc_init();
    292             memset(hwaddr, 0, sizeof(hwaddr));
    293 
    294             if (ifc_get_info(argv[2], &addr.s_addr, &prefixLength, &flags)) {
    295                 cli->sendMsg(ResponseCode::OperationFailed, "Interface not found", true);
    296                 ifc_close();
    297                 return 0;
    298             }
    299 
    300             if (ifc_get_hwaddr(argv[2], (void *) hwaddr)) {
    301                 ALOGW("Failed to retrieve HW addr for %s (%s)", argv[2], strerror(errno));
    302             }
    303 
    304             char *addr_s = strdup(inet_ntoa(addr));
    305             const char *updown, *brdcst, *loopbk, *ppp, *running, *multi;
    306 
    307             updown =  (flags & IFF_UP)           ? "up" : "down";
    308             brdcst =  (flags & IFF_BROADCAST)    ? " broadcast" : "";
    309             loopbk =  (flags & IFF_LOOPBACK)     ? " loopback" : "";
    310             ppp =     (flags & IFF_POINTOPOINT)  ? " point-to-point" : "";
    311             running = (flags & IFF_RUNNING)      ? " running" : "";
    312             multi =   (flags & IFF_MULTICAST)    ? " multicast" : "";
    313 
    314             char *flag_s;
    315 
    316             asprintf(&flag_s, "%s%s%s%s%s%s", updown, brdcst, loopbk, ppp, running, multi);
    317 
    318             char *msg = NULL;
    319             asprintf(&msg, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x %s %d %s",
    320                      hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5],
    321                      addr_s, prefixLength, flag_s);
    322 
    323             cli->sendMsg(ResponseCode::InterfaceGetCfgResult, msg, false);
    324 
    325             free(addr_s);
    326             free(flag_s);
    327             free(msg);
    328 
    329             ifc_close();
    330             return 0;
    331         } else if (!strcmp(argv[1], "setcfg")) {
    332             // arglist: iface [addr prefixLength] flags
    333             if (argc < 4) {
    334                 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
    335                 return 0;
    336             }
    337             ALOGD("Setting iface cfg");
    338 
    339             struct in_addr addr;
    340             int index = 5;
    341 
    342             ifc_init();
    343 
    344             if (!inet_aton(argv[3], &addr)) {
    345                 // Handle flags only case
    346                 index = 3;
    347             } else {
    348                 if (ifc_set_addr(argv[2], 0)) {
    349                     cli->sendMsg(ResponseCode::OperationFailed, "Failed to clear address", true);
    350                     ifc_close();
    351                     return 0;
    352                 }
    353                 if (addr.s_addr != 0) {
    354                     if (ifc_add_address(argv[2], argv[3], atoi(argv[4]))) {
    355                         cli->sendMsg(ResponseCode::OperationFailed, "Failed to set address", true);
    356                         ifc_close();
    357                         return 0;
    358                     }
    359                 }
    360             }
    361 
    362             /* Process flags */
    363             for (int i = index; i < argc; i++) {
    364                 char *flag = argv[i];
    365                 if (!strcmp(flag, "up")) {
    366                     ALOGD("Trying to bring up %s", argv[2]);
    367                     if (ifc_up(argv[2])) {
    368                         ALOGE("Error upping interface");
    369                         cli->sendMsg(ResponseCode::OperationFailed, "Failed to up interface", true);
    370                         ifc_close();
    371                         return 0;
    372                     }
    373                 } else if (!strcmp(flag, "down")) {
    374                     ALOGD("Trying to bring down %s", argv[2]);
    375                     if (ifc_down(argv[2])) {
    376                         ALOGE("Error downing interface");
    377                         cli->sendMsg(ResponseCode::OperationFailed, "Failed to down interface", true);
    378                         ifc_close();
    379                         return 0;
    380                     }
    381                 } else if (!strcmp(flag, "broadcast")) {
    382                     // currently ignored
    383                 } else if (!strcmp(flag, "multicast")) {
    384                     // currently ignored
    385                 } else if (!strcmp(flag, "running")) {
    386                     // currently ignored
    387                 } else if (!strcmp(flag, "loopback")) {
    388                     // currently ignored
    389                 } else if (!strcmp(flag, "point-to-point")) {
    390                     // currently ignored
    391                 } else {
    392                     cli->sendMsg(ResponseCode::CommandParameterError, "Flag unsupported", false);
    393                     ifc_close();
    394                     return 0;
    395                 }
    396             }
    397 
    398             cli->sendMsg(ResponseCode::CommandOkay, "Interface configuration set", false);
    399             ifc_close();
    400             return 0;
    401         } else if (!strcmp(argv[1], "clearaddrs")) {
    402             // arglist: iface
    403             ALOGD("Clearing all IP addresses on %s", argv[2]);
    404 
    405             ifc_clear_addresses(argv[2]);
    406 
    407             cli->sendMsg(ResponseCode::CommandOkay, "Interface IP addresses cleared", false);
    408             return 0;
    409         } else if (!strcmp(argv[1], "ipv6privacyextensions")) {
    410             if (argc != 4) {
    411                 cli->sendMsg(ResponseCode::CommandSyntaxError,
    412                         "Usage: interface ipv6privacyextensions <interface> <enable|disable>",
    413                         false);
    414                 return 0;
    415             }
    416             int enable = !strncmp(argv[3], "enable", 7);
    417             if (gCtls->interfaceCtrl.setIPv6PrivacyExtensions(argv[2], enable) == 0) {
    418                 cli->sendMsg(ResponseCode::CommandOkay, "IPv6 privacy extensions changed", false);
    419             } else {
    420                 cli->sendMsg(ResponseCode::OperationFailed,
    421                         "Failed to set ipv6 privacy extensions", true);
    422             }
    423             return 0;
    424         } else if (!strcmp(argv[1], "ipv6")) {
    425             if (argc != 4) {
    426                 cli->sendMsg(ResponseCode::CommandSyntaxError,
    427                         "Usage: interface ipv6 <interface> <enable|disable>",
    428                         false);
    429                 return 0;
    430             }
    431 
    432             int enable = !strncmp(argv[3], "enable", 7);
    433             if (gCtls->interfaceCtrl.setEnableIPv6(argv[2], enable) == 0) {
    434                 cli->sendMsg(ResponseCode::CommandOkay, "IPv6 state changed", false);
    435             } else {
    436                 cli->sendMsg(ResponseCode::OperationFailed,
    437                         "Failed to change IPv6 state", true);
    438             }
    439             return 0;
    440         } else if (!strcmp(argv[1], "ipv6ndoffload")) {
    441             if (argc != 4) {
    442                 cli->sendMsg(ResponseCode::CommandSyntaxError,
    443                         "Usage: interface ipv6ndoffload <interface> <enable|disable>",
    444                         false);
    445                 return 0;
    446             }
    447             int enable = !strncmp(argv[3], "enable", 7);
    448             if (gCtls->interfaceCtrl.setIPv6NdOffload(argv[2], enable) == 0) {
    449                 cli->sendMsg(ResponseCode::CommandOkay, "IPv6 ND offload changed", false);
    450             } else {
    451                 cli->sendMsg(ResponseCode::OperationFailed,
    452                         "Failed to change IPv6 ND offload state", true);
    453             }
    454             return 0;
    455         } else if (!strcmp(argv[1], "setmtu")) {
    456             if (argc != 4) {
    457                 cli->sendMsg(ResponseCode::CommandSyntaxError,
    458                         "Usage: interface setmtu <interface> <val>", false);
    459                 return 0;
    460             }
    461             if (gCtls->interfaceCtrl.setMtu(argv[2], argv[3]) == 0) {
    462                 cli->sendMsg(ResponseCode::CommandOkay, "MTU changed", false);
    463             } else {
    464                 cli->sendMsg(ResponseCode::OperationFailed,
    465                         "Failed to set MTU", true);
    466             }
    467             return 0;
    468         } else {
    469             cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown interface cmd", false);
    470             return 0;
    471         }
    472     }
    473     return 0;
    474 }
    475 
    476 
    477 CommandListener::ListTtysCmd::ListTtysCmd() :
    478                  NetdCommand("list_ttys") {
    479 }
    480 
    481 int CommandListener::ListTtysCmd::runCommand(SocketClient *cli,
    482                                              int /* argc */, char ** /* argv */) {
    483     TtyCollection *tlist = gCtls->pppCtrl.getTtyList();
    484     TtyCollection::iterator it;
    485 
    486     for (it = tlist->begin(); it != tlist->end(); ++it) {
    487         cli->sendMsg(ResponseCode::TtyListResult, *it, false);
    488     }
    489 
    490     cli->sendMsg(ResponseCode::CommandOkay, "Ttys listed.", false);
    491     return 0;
    492 }
    493 
    494 CommandListener::IpFwdCmd::IpFwdCmd() :
    495                  NetdCommand("ipfwd") {
    496 }
    497 
    498 int CommandListener::IpFwdCmd::runCommand(SocketClient *cli, int argc, char **argv) {
    499     bool matched = false;
    500     bool success;
    501 
    502     if (argc == 2) {
    503         //   0     1
    504         // ipfwd status
    505         if (!strcmp(argv[1], "status")) {
    506             char *tmp = NULL;
    507 
    508             asprintf(&tmp, "Forwarding %s",
    509                      ((gCtls->tetherCtrl.forwardingRequestCount() > 0) ? "enabled" : "disabled"));
    510             cli->sendMsg(ResponseCode::IpFwdStatusResult, tmp, false);
    511             free(tmp);
    512             return 0;
    513         }
    514     } else if (argc == 3) {
    515         //  0      1         2
    516         // ipfwd enable  <requester>
    517         // ipfwd disable <requester>
    518         if (!strcmp(argv[1], "enable")) {
    519             matched = true;
    520             success = gCtls->tetherCtrl.enableForwarding(argv[2]);
    521         } else if (!strcmp(argv[1], "disable")) {
    522             matched = true;
    523             success = gCtls->tetherCtrl.disableForwarding(argv[2]);
    524         }
    525     } else if (argc == 4) {
    526         //  0      1      2     3
    527         // ipfwd  add   wlan0 dummy0
    528         // ipfwd remove wlan0 dummy0
    529         int ret = 0;
    530         if (!strcmp(argv[1], "add")) {
    531             matched = true;
    532             ret = RouteController::enableTethering(argv[2], argv[3]);
    533         } else if (!strcmp(argv[1], "remove")) {
    534             matched = true;
    535             ret = RouteController::disableTethering(argv[2], argv[3]);
    536         }
    537         success = (ret == 0);
    538         errno = -ret;
    539     }
    540 
    541     if (!matched) {
    542         cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown ipfwd cmd", false);
    543         return 0;
    544     }
    545 
    546     if (success) {
    547         cli->sendMsg(ResponseCode::CommandOkay, "ipfwd operation succeeded", false);
    548     } else {
    549         cli->sendMsg(ResponseCode::OperationFailed, "ipfwd operation failed", true);
    550     }
    551     return 0;
    552 }
    553 
    554 CommandListener::TetherCmd::TetherCmd() :
    555                  NetdCommand("tether") {
    556 }
    557 
    558 int CommandListener::TetherCmd::runCommand(SocketClient *cli,
    559                                                       int argc, char **argv) {
    560     int rc = 0;
    561 
    562     if (argc < 2) {
    563         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
    564         return 0;
    565     }
    566 
    567     if (!strcmp(argv[1], "stop")) {
    568         rc = gCtls->tetherCtrl.stopTethering();
    569     } else if (!strcmp(argv[1], "status")) {
    570         char *tmp = NULL;
    571 
    572         asprintf(&tmp, "Tethering services %s",
    573                  (gCtls->tetherCtrl.isTetheringStarted() ? "started" : "stopped"));
    574         cli->sendMsg(ResponseCode::TetherStatusResult, tmp, false);
    575         free(tmp);
    576         return 0;
    577     } else if (argc == 3) {
    578         if (!strcmp(argv[1], "interface") && !strcmp(argv[2], "list")) {
    579             InterfaceCollection *ilist = gCtls->tetherCtrl.getTetheredInterfaceList();
    580             InterfaceCollection::iterator it;
    581             for (it = ilist->begin(); it != ilist->end(); ++it) {
    582                 cli->sendMsg(ResponseCode::TetherInterfaceListResult, *it, false);
    583             }
    584         } else if (!strcmp(argv[1], "dns") && !strcmp(argv[2], "list")) {
    585             char netIdStr[UINT32_STRLEN];
    586             snprintf(netIdStr, sizeof(netIdStr), "%u", gCtls->tetherCtrl.getDnsNetId());
    587             cli->sendMsg(ResponseCode::TetherDnsFwdNetIdResult, netIdStr, false);
    588 
    589             for (const auto &fwdr : *(gCtls->tetherCtrl.getDnsForwarders())) {
    590                 cli->sendMsg(ResponseCode::TetherDnsFwdTgtListResult, fwdr.c_str(), false);
    591             }
    592         }
    593     } else {
    594         /*
    595          * These commands take a minimum of 4 arguments
    596          */
    597         if (argc < 4) {
    598             cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
    599             return 0;
    600         }
    601 
    602         if (!strcmp(argv[1], "start")) {
    603             if (argc % 2 == 1) {
    604                 cli->sendMsg(ResponseCode::CommandSyntaxError, "Bad number of arguments", false);
    605                 return 0;
    606             }
    607 
    608             const int num_addrs = argc - 2;
    609             // TODO: consider moving this validation into TetherController.
    610             struct in_addr tmp_addr;
    611             for (int arg_index = 2; arg_index < argc; arg_index++) {
    612                 if (!inet_aton(argv[arg_index], &tmp_addr)) {
    613                     cli->sendMsg(ResponseCode::CommandParameterError, "Invalid address", false);
    614                     return 0;
    615                 }
    616             }
    617 
    618             rc = gCtls->tetherCtrl.startTethering(num_addrs, &(argv[2]));
    619         } else if (!strcmp(argv[1], "interface")) {
    620             if (!strcmp(argv[2], "add")) {
    621                 rc = gCtls->tetherCtrl.tetherInterface(argv[3]);
    622             } else if (!strcmp(argv[2], "remove")) {
    623                 rc = gCtls->tetherCtrl.untetherInterface(argv[3]);
    624             /* else if (!strcmp(argv[2], "list")) handled above */
    625             } else {
    626                 cli->sendMsg(ResponseCode::CommandParameterError,
    627                              "Unknown tether interface operation", false);
    628                 return 0;
    629             }
    630         } else if (!strcmp(argv[1], "dns")) {
    631             if (!strcmp(argv[2], "set")) {
    632                 if (argc < 5) {
    633                     cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
    634                     return 0;
    635                 }
    636                 unsigned netId = stringToNetId(argv[3]);
    637                 rc = gCtls->tetherCtrl.setDnsForwarders(netId, &argv[4], argc - 4);
    638             /* else if (!strcmp(argv[2], "list")) handled above */
    639             } else {
    640                 cli->sendMsg(ResponseCode::CommandParameterError,
    641                              "Unknown tether interface operation", false);
    642                 return 0;
    643             }
    644         } else {
    645             cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown tether cmd", false);
    646             return 0;
    647         }
    648     }
    649 
    650     if (!rc) {
    651         cli->sendMsg(ResponseCode::CommandOkay, "Tether operation succeeded", false);
    652     } else {
    653         cli->sendMsg(ResponseCode::OperationFailed, "Tether operation failed", true);
    654     }
    655 
    656     return 0;
    657 }
    658 
    659 CommandListener::NatCmd::NatCmd() :
    660                  NetdCommand("nat") {
    661 }
    662 
    663 int CommandListener::NatCmd::runCommand(SocketClient *cli,
    664                                                       int argc, char **argv) {
    665     int rc = 0;
    666 
    667     if (argc < 5) {
    668         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
    669         return 0;
    670     }
    671 
    672     //  0     1       2        3
    673     // nat  enable intiface extiface
    674     // nat disable intiface extiface
    675     if (!strcmp(argv[1], "enable") && argc >= 4) {
    676         rc = gCtls->natCtrl.enableNat(argv[2], argv[3]);
    677         if(!rc) {
    678             /* Ignore ifaces for now. */
    679             rc = gCtls->bandwidthCtrl.setGlobalAlertInForwardChain();
    680         }
    681     } else if (!strcmp(argv[1], "disable") && argc >= 4) {
    682         /* Ignore ifaces for now. */
    683         rc = gCtls->bandwidthCtrl.removeGlobalAlertInForwardChain();
    684         rc |= gCtls->natCtrl.disableNat(argv[2], argv[3]);
    685     } else {
    686         cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown nat cmd", false);
    687         return 0;
    688     }
    689 
    690     if (!rc) {
    691         cli->sendMsg(ResponseCode::CommandOkay, "Nat operation succeeded", false);
    692     } else {
    693         cli->sendMsg(ResponseCode::OperationFailed, "Nat operation failed", true);
    694     }
    695 
    696     return 0;
    697 }
    698 
    699 CommandListener::PppdCmd::PppdCmd() :
    700                  NetdCommand("pppd") {
    701 }
    702 
    703 int CommandListener::PppdCmd::runCommand(SocketClient *cli,
    704                                                       int argc, char **argv) {
    705     int rc = 0;
    706 
    707     if (argc < 3) {
    708         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
    709         return 0;
    710     }
    711 
    712     if (!strcmp(argv[1], "attach")) {
    713         struct in_addr l, r, dns1, dns2;
    714 
    715         memset(&dns1, 0, sizeof(struct in_addr));
    716         memset(&dns2, 0, sizeof(struct in_addr));
    717 
    718         if (!inet_aton(argv[3], &l)) {
    719             cli->sendMsg(ResponseCode::CommandParameterError, "Invalid local address", false);
    720             return 0;
    721         }
    722         if (!inet_aton(argv[4], &r)) {
    723             cli->sendMsg(ResponseCode::CommandParameterError, "Invalid remote address", false);
    724             return 0;
    725         }
    726         if ((argc > 3) && (!inet_aton(argv[5], &dns1))) {
    727             cli->sendMsg(ResponseCode::CommandParameterError, "Invalid dns1 address", false);
    728             return 0;
    729         }
    730         if ((argc > 4) && (!inet_aton(argv[6], &dns2))) {
    731             cli->sendMsg(ResponseCode::CommandParameterError, "Invalid dns2 address", false);
    732             return 0;
    733         }
    734         rc = gCtls->pppCtrl.attachPppd(argv[2], l, r, dns1, dns2);
    735     } else if (!strcmp(argv[1], "detach")) {
    736         rc = gCtls->pppCtrl.detachPppd(argv[2]);
    737     } else {
    738         cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown pppd cmd", false);
    739         return 0;
    740     }
    741 
    742     if (!rc) {
    743         cli->sendMsg(ResponseCode::CommandOkay, "Pppd operation succeeded", false);
    744     } else {
    745         cli->sendMsg(ResponseCode::OperationFailed, "Pppd operation failed", true);
    746     }
    747 
    748     return 0;
    749 }
    750 
    751 CommandListener::SoftapCmd::SoftapCmd() :
    752                  NetdCommand("softap") {
    753 }
    754 
    755 int CommandListener::SoftapCmd::runCommand(SocketClient *cli,
    756                                         int argc, char **argv) {
    757     int rc = ResponseCode::SoftapStatusResult;
    758     char *retbuf = NULL;
    759 
    760     if (gCtls == nullptr) {
    761       cli->sendMsg(ResponseCode::ServiceStartFailed, "SoftAP is not available", false);
    762       return -1;
    763     }
    764     if (argc < 2) {
    765         cli->sendMsg(ResponseCode::CommandSyntaxError,
    766                      "Missing argument in a SoftAP command", false);
    767         return 0;
    768     }
    769 
    770     if (!strcmp(argv[1], "startap")) {
    771         rc = gCtls->softapCtrl.startSoftap();
    772     } else if (!strcmp(argv[1], "stopap")) {
    773         rc = gCtls->softapCtrl.stopSoftap();
    774     } else if (!strcmp(argv[1], "fwreload")) {
    775         rc = gCtls->softapCtrl.fwReloadSoftap(argc, argv);
    776     } else if (!strcmp(argv[1], "status")) {
    777         asprintf(&retbuf, "Softap service %s running",
    778                  (gCtls->softapCtrl.isSoftapStarted() ? "is" : "is not"));
    779         cli->sendMsg(rc, retbuf, false);
    780         free(retbuf);
    781         return 0;
    782     } else if (!strcmp(argv[1], "set")) {
    783         rc = gCtls->softapCtrl.setSoftap(argc, argv);
    784     } else {
    785         cli->sendMsg(ResponseCode::CommandSyntaxError, "Unrecognized SoftAP command", false);
    786         return 0;
    787     }
    788 
    789     if (rc >= 400 && rc < 600)
    790       cli->sendMsg(rc, "SoftAP command has failed", false);
    791     else
    792       cli->sendMsg(rc, "Ok", false);
    793 
    794     return 0;
    795 }
    796 
    797 CommandListener::ResolverCmd::ResolverCmd() :
    798         NetdCommand("resolver") {
    799 }
    800 
    801 int CommandListener::ResolverCmd::runCommand(SocketClient *cli, int argc, char **margv) {
    802     int rc = 0;
    803     const char **argv = const_cast<const char **>(margv);
    804 
    805     if (argc < 3) {
    806         cli->sendMsg(ResponseCode::CommandSyntaxError, "Resolver missing arguments", false);
    807         return 0;
    808     }
    809 
    810     unsigned netId = stringToNetId(argv[2]);
    811     // TODO: Consider making NetworkController.isValidNetwork() public
    812     // and making that check here.
    813 
    814     if (!strcmp(argv[1], "setnetdns")) {
    815         if (!parseAndExecuteSetNetDns(netId, argc, argv)) {
    816             cli->sendMsg(ResponseCode::CommandSyntaxError,
    817                     "Wrong number of or invalid arguments to resolver setnetdns", false);
    818             return 0;
    819         }
    820     } else if (!strcmp(argv[1], "clearnetdns")) { // "resolver clearnetdns <netId>"
    821         if (argc == 3) {
    822             rc = gCtls->resolverCtrl.clearDnsServers(netId);
    823         } else {
    824             cli->sendMsg(ResponseCode::CommandSyntaxError,
    825                     "Wrong number of arguments to resolver clearnetdns", false);
    826             return 0;
    827         }
    828     } else {
    829         cli->sendMsg(ResponseCode::CommandSyntaxError,"Resolver unknown command", false);
    830         return 0;
    831     }
    832 
    833     if (!rc) {
    834         cli->sendMsg(ResponseCode::CommandOkay, "Resolver command succeeded", false);
    835     } else {
    836         cli->sendMsg(ResponseCode::OperationFailed, "Resolver command failed", true);
    837     }
    838 
    839     return 0;
    840 }
    841 
    842 bool CommandListener::ResolverCmd::parseAndExecuteSetNetDns(int netId, int argc,
    843         const char** argv) {
    844     // "resolver setnetdns <netId> <domains> <dns1> [<dns2> ...] [--params <params>]"
    845     // TODO: This code has to be replaced by a Binder call ASAP
    846     if (argc < 5) {
    847         return false;
    848     }
    849     int end = argc;
    850     __res_params params;
    851     const __res_params* paramsPtr = nullptr;
    852     if (end > 6 && !strcmp(argv[end - 2], "--params")) {
    853         const char* paramsStr = argv[end - 1];
    854         end -= 2;
    855         if (sscanf(paramsStr, "%hu %hhu %hhu %hhu", &params.sample_validity,
    856                 &params.success_threshold, &params.min_samples, &params.max_samples) != 4) {
    857             return false;
    858         }
    859         paramsPtr = &params;
    860     }
    861     return gCtls->resolverCtrl.setDnsServers(netId, argv[3], &argv[4], end - 4, paramsPtr) == 0;
    862 }
    863 
    864 CommandListener::BandwidthControlCmd::BandwidthControlCmd() :
    865     NetdCommand("bandwidth") {
    866 }
    867 
    868 void CommandListener::BandwidthControlCmd::sendGenericSyntaxError(SocketClient *cli, const char *usageMsg) {
    869     char *msg;
    870     asprintf(&msg, "Usage: bandwidth %s", usageMsg);
    871     cli->sendMsg(ResponseCode::CommandSyntaxError, msg, false);
    872     free(msg);
    873 }
    874 
    875 void CommandListener::BandwidthControlCmd::sendGenericOkFail(SocketClient *cli, int cond) {
    876     if (!cond) {
    877         cli->sendMsg(ResponseCode::CommandOkay, "Bandwidth command succeeeded", false);
    878     } else {
    879         cli->sendMsg(ResponseCode::OperationFailed, "Bandwidth command failed", false);
    880     }
    881 }
    882 
    883 void CommandListener::BandwidthControlCmd::sendGenericOpFailed(SocketClient *cli, const char *errMsg) {
    884     cli->sendMsg(ResponseCode::OperationFailed, errMsg, false);
    885 }
    886 
    887 int CommandListener::BandwidthControlCmd::runCommand(SocketClient *cli, int argc, char **argv) {
    888     if (argc < 2) {
    889         sendGenericSyntaxError(cli, "<cmds> <args...>");
    890         return 0;
    891     }
    892 
    893     ALOGV("bwctrlcmd: argc=%d %s %s ...", argc, argv[0], argv[1]);
    894 
    895     if (!strcmp(argv[1], "enable")) {
    896         int rc = gCtls->bandwidthCtrl.enableBandwidthControl(true);
    897         sendGenericOkFail(cli, rc);
    898         return 0;
    899 
    900     }
    901     if (!strcmp(argv[1], "disable")) {
    902         int rc = gCtls->bandwidthCtrl.disableBandwidthControl();
    903         sendGenericOkFail(cli, rc);
    904         return 0;
    905 
    906     }
    907     if (!strcmp(argv[1], "removequota") || !strcmp(argv[1], "rq")) {
    908         if (argc != 3) {
    909             sendGenericSyntaxError(cli, "removequota <interface>");
    910             return 0;
    911         }
    912         int rc = gCtls->bandwidthCtrl.removeInterfaceSharedQuota(argv[2]);
    913         sendGenericOkFail(cli, rc);
    914         return 0;
    915 
    916     }
    917     if (!strcmp(argv[1], "getquota") || !strcmp(argv[1], "gq")) {
    918         int64_t bytes;
    919         if (argc != 2) {
    920             sendGenericSyntaxError(cli, "getquota");
    921             return 0;
    922         }
    923         int rc = gCtls->bandwidthCtrl.getInterfaceSharedQuota(&bytes);
    924         if (rc) {
    925             sendGenericOpFailed(cli, "Failed to get quota");
    926             return 0;
    927         }
    928 
    929         char *msg;
    930         asprintf(&msg, "%" PRId64, bytes);
    931         cli->sendMsg(ResponseCode::QuotaCounterResult, msg, false);
    932         free(msg);
    933         return 0;
    934 
    935     }
    936     if (!strcmp(argv[1], "getiquota") || !strcmp(argv[1], "giq")) {
    937         int64_t bytes;
    938         if (argc != 3) {
    939             sendGenericSyntaxError(cli, "getiquota <iface>");
    940             return 0;
    941         }
    942 
    943         int rc = gCtls->bandwidthCtrl.getInterfaceQuota(argv[2], &bytes);
    944         if (rc) {
    945             sendGenericOpFailed(cli, "Failed to get quota");
    946             return 0;
    947         }
    948         char *msg;
    949         asprintf(&msg, "%" PRId64, bytes);
    950         cli->sendMsg(ResponseCode::QuotaCounterResult, msg, false);
    951         free(msg);
    952         return 0;
    953 
    954     }
    955     if (!strcmp(argv[1], "setquota") || !strcmp(argv[1], "sq")) {
    956         if (argc != 4) {
    957             sendGenericSyntaxError(cli, "setquota <interface> <bytes>");
    958             return 0;
    959         }
    960         int rc = gCtls->bandwidthCtrl.setInterfaceSharedQuota(argv[2], atoll(argv[3]));
    961         sendGenericOkFail(cli, rc);
    962         return 0;
    963     }
    964     if (!strcmp(argv[1], "setquotas") || !strcmp(argv[1], "sqs")) {
    965         int rc;
    966         if (argc < 4) {
    967             sendGenericSyntaxError(cli, "setquotas <bytes> <interface> ...");
    968             return 0;
    969         }
    970 
    971         for (int q = 3; argc >= 4; q++, argc--) {
    972             rc = gCtls->bandwidthCtrl.setInterfaceSharedQuota(argv[q], atoll(argv[2]));
    973             if (rc) {
    974                 char *msg;
    975                 asprintf(&msg, "bandwidth setquotas %s %s failed", argv[2], argv[q]);
    976                 cli->sendMsg(ResponseCode::OperationFailed,
    977                              msg, false);
    978                 free(msg);
    979                 return 0;
    980             }
    981         }
    982         sendGenericOkFail(cli, rc);
    983         return 0;
    984 
    985     }
    986     if (!strcmp(argv[1], "removequotas") || !strcmp(argv[1], "rqs")) {
    987         int rc;
    988         if (argc < 3) {
    989             sendGenericSyntaxError(cli, "removequotas <interface> ...");
    990             return 0;
    991         }
    992 
    993         for (int q = 2; argc >= 3; q++, argc--) {
    994             rc = gCtls->bandwidthCtrl.removeInterfaceSharedQuota(argv[q]);
    995             if (rc) {
    996                 char *msg;
    997                 asprintf(&msg, "bandwidth removequotas %s failed", argv[q]);
    998                 cli->sendMsg(ResponseCode::OperationFailed,
    999                              msg, false);
   1000                 free(msg);
   1001                 return 0;
   1002             }
   1003         }
   1004         sendGenericOkFail(cli, rc);
   1005         return 0;
   1006 
   1007     }
   1008     if (!strcmp(argv[1], "removeiquota") || !strcmp(argv[1], "riq")) {
   1009         if (argc != 3) {
   1010             sendGenericSyntaxError(cli, "removeiquota <interface>");
   1011             return 0;
   1012         }
   1013         int rc = gCtls->bandwidthCtrl.removeInterfaceQuota(argv[2]);
   1014         sendGenericOkFail(cli, rc);
   1015         return 0;
   1016 
   1017     }
   1018     if (!strcmp(argv[1], "setiquota") || !strcmp(argv[1], "siq")) {
   1019         if (argc != 4) {
   1020             sendGenericSyntaxError(cli, "setiquota <interface> <bytes>");
   1021             return 0;
   1022         }
   1023         int rc = gCtls->bandwidthCtrl.setInterfaceQuota(argv[2], atoll(argv[3]));
   1024         sendGenericOkFail(cli, rc);
   1025         return 0;
   1026 
   1027     }
   1028     if (!strcmp(argv[1], "addnaughtyapps") || !strcmp(argv[1], "ana")) {
   1029         if (argc < 3) {
   1030             sendGenericSyntaxError(cli, "addnaughtyapps <appUid> ...");
   1031             return 0;
   1032         }
   1033         int rc = gCtls->bandwidthCtrl.addNaughtyApps(argc - 2, argv + 2);
   1034         sendGenericOkFail(cli, rc);
   1035         return 0;
   1036 
   1037 
   1038     }
   1039     if (!strcmp(argv[1], "removenaughtyapps") || !strcmp(argv[1], "rna")) {
   1040         if (argc < 3) {
   1041             sendGenericSyntaxError(cli, "removenaughtyapps <appUid> ...");
   1042             return 0;
   1043         }
   1044         int rc = gCtls->bandwidthCtrl.removeNaughtyApps(argc - 2, argv + 2);
   1045         sendGenericOkFail(cli, rc);
   1046         return 0;
   1047     }
   1048     if (!strcmp(argv[1], "addniceapps") || !strcmp(argv[1], "aha")) {
   1049         if (argc < 3) {
   1050             sendGenericSyntaxError(cli, "addniceapps <appUid> ...");
   1051             return 0;
   1052         }
   1053         int rc = gCtls->bandwidthCtrl.addNiceApps(argc - 2, argv + 2);
   1054         sendGenericOkFail(cli, rc);
   1055         return 0;
   1056     }
   1057     if (!strcmp(argv[1], "removeniceapps") || !strcmp(argv[1], "rha")) {
   1058         if (argc < 3) {
   1059             sendGenericSyntaxError(cli, "removeniceapps <appUid> ...");
   1060             return 0;
   1061         }
   1062         int rc = gCtls->bandwidthCtrl.removeNiceApps(argc - 2, argv + 2);
   1063         sendGenericOkFail(cli, rc);
   1064         return 0;
   1065     }
   1066     if (!strcmp(argv[1], "setglobalalert") || !strcmp(argv[1], "sga")) {
   1067         if (argc != 3) {
   1068             sendGenericSyntaxError(cli, "setglobalalert <bytes>");
   1069             return 0;
   1070         }
   1071         int rc = gCtls->bandwidthCtrl.setGlobalAlert(atoll(argv[2]));
   1072         sendGenericOkFail(cli, rc);
   1073         return 0;
   1074     }
   1075     if (!strcmp(argv[1], "debugsettetherglobalalert") || !strcmp(argv[1], "dstga")) {
   1076         if (argc != 4) {
   1077             sendGenericSyntaxError(cli, "debugsettetherglobalalert <interface0> <interface1>");
   1078             return 0;
   1079         }
   1080         /* We ignore the interfaces for now. */
   1081         int rc = gCtls->bandwidthCtrl.setGlobalAlertInForwardChain();
   1082         sendGenericOkFail(cli, rc);
   1083         return 0;
   1084 
   1085     }
   1086     if (!strcmp(argv[1], "removeglobalalert") || !strcmp(argv[1], "rga")) {
   1087         if (argc != 2) {
   1088             sendGenericSyntaxError(cli, "removeglobalalert");
   1089             return 0;
   1090         }
   1091         int rc = gCtls->bandwidthCtrl.removeGlobalAlert();
   1092         sendGenericOkFail(cli, rc);
   1093         return 0;
   1094 
   1095     }
   1096     if (!strcmp(argv[1], "debugremovetetherglobalalert") || !strcmp(argv[1], "drtga")) {
   1097         if (argc != 4) {
   1098             sendGenericSyntaxError(cli, "debugremovetetherglobalalert <interface0> <interface1>");
   1099             return 0;
   1100         }
   1101         /* We ignore the interfaces for now. */
   1102         int rc = gCtls->bandwidthCtrl.removeGlobalAlertInForwardChain();
   1103         sendGenericOkFail(cli, rc);
   1104         return 0;
   1105 
   1106     }
   1107     if (!strcmp(argv[1], "setsharedalert") || !strcmp(argv[1], "ssa")) {
   1108         if (argc != 3) {
   1109             sendGenericSyntaxError(cli, "setsharedalert <bytes>");
   1110             return 0;
   1111         }
   1112         int rc = gCtls->bandwidthCtrl.setSharedAlert(atoll(argv[2]));
   1113         sendGenericOkFail(cli, rc);
   1114         return 0;
   1115 
   1116     }
   1117     if (!strcmp(argv[1], "removesharedalert") || !strcmp(argv[1], "rsa")) {
   1118         if (argc != 2) {
   1119             sendGenericSyntaxError(cli, "removesharedalert");
   1120             return 0;
   1121         }
   1122         int rc = gCtls->bandwidthCtrl.removeSharedAlert();
   1123         sendGenericOkFail(cli, rc);
   1124         return 0;
   1125 
   1126     }
   1127     if (!strcmp(argv[1], "setinterfacealert") || !strcmp(argv[1], "sia")) {
   1128         if (argc != 4) {
   1129             sendGenericSyntaxError(cli, "setinterfacealert <interface> <bytes>");
   1130             return 0;
   1131         }
   1132         int rc = gCtls->bandwidthCtrl.setInterfaceAlert(argv[2], atoll(argv[3]));
   1133         sendGenericOkFail(cli, rc);
   1134         return 0;
   1135 
   1136     }
   1137     if (!strcmp(argv[1], "removeinterfacealert") || !strcmp(argv[1], "ria")) {
   1138         if (argc != 3) {
   1139             sendGenericSyntaxError(cli, "removeinterfacealert <interface>");
   1140             return 0;
   1141         }
   1142         int rc = gCtls->bandwidthCtrl.removeInterfaceAlert(argv[2]);
   1143         sendGenericOkFail(cli, rc);
   1144         return 0;
   1145 
   1146     }
   1147     if (!strcmp(argv[1], "gettetherstats") || !strcmp(argv[1], "gts")) {
   1148         BandwidthController::TetherStats tetherStats;
   1149         std::string extraProcessingInfo = "";
   1150         if (argc < 2 || argc > 4) {
   1151             sendGenericSyntaxError(cli, "gettetherstats [<intInterface> <extInterface>]");
   1152             return 0;
   1153         }
   1154         tetherStats.intIface = argc > 2 ? argv[2] : "";
   1155         tetherStats.extIface = argc > 3 ? argv[3] : "";
   1156         // No filtering requested and there are no interface pairs to lookup.
   1157         if (argc <= 2 && gCtls->natCtrl.ifacePairList.empty()) {
   1158             cli->sendMsg(ResponseCode::CommandOkay, "Tethering stats list completed", false);
   1159             return 0;
   1160         }
   1161         int rc = gCtls->bandwidthCtrl.getTetherStats(cli, tetherStats, extraProcessingInfo);
   1162         if (rc) {
   1163                 extraProcessingInfo.insert(0, "Failed to get tethering stats.\n");
   1164                 sendGenericOpFailed(cli, extraProcessingInfo.c_str());
   1165                 return 0;
   1166         }
   1167         return 0;
   1168 
   1169     }
   1170 
   1171     cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown bandwidth cmd", false);
   1172     return 0;
   1173 }
   1174 
   1175 CommandListener::IdletimerControlCmd::IdletimerControlCmd() :
   1176     NetdCommand("idletimer") {
   1177 }
   1178 
   1179 int CommandListener::IdletimerControlCmd::runCommand(SocketClient *cli, int argc, char **argv) {
   1180   // TODO(ashish): Change the error statements
   1181     if (argc < 2) {
   1182         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
   1183         return 0;
   1184     }
   1185 
   1186     ALOGV("idletimerctrlcmd: argc=%d %s %s ...", argc, argv[0], argv[1]);
   1187 
   1188     if (!strcmp(argv[1], "enable")) {
   1189       if (0 != gCtls->idletimerCtrl.enableIdletimerControl()) {
   1190         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
   1191       } else {
   1192         cli->sendMsg(ResponseCode::CommandOkay, "Enable success", false);
   1193       }
   1194       return 0;
   1195 
   1196     }
   1197     if (!strcmp(argv[1], "disable")) {
   1198       if (0 != gCtls->idletimerCtrl.disableIdletimerControl()) {
   1199         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
   1200       } else {
   1201         cli->sendMsg(ResponseCode::CommandOkay, "Disable success", false);
   1202       }
   1203       return 0;
   1204     }
   1205     if (!strcmp(argv[1], "add")) {
   1206         if (argc != 5) {
   1207             cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
   1208             return 0;
   1209         }
   1210         if(0 != gCtls->idletimerCtrl.addInterfaceIdletimer(
   1211                                         argv[2], atoi(argv[3]), argv[4])) {
   1212           cli->sendMsg(ResponseCode::OperationFailed, "Failed to add interface", false);
   1213         } else {
   1214           cli->sendMsg(ResponseCode::CommandOkay,  "Add success", false);
   1215         }
   1216         return 0;
   1217     }
   1218     if (!strcmp(argv[1], "remove")) {
   1219         if (argc != 5) {
   1220             cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
   1221             return 0;
   1222         }
   1223         // ashish: fixme timeout
   1224         if (0 != gCtls->idletimerCtrl.removeInterfaceIdletimer(
   1225                                         argv[2], atoi(argv[3]), argv[4])) {
   1226           cli->sendMsg(ResponseCode::OperationFailed, "Failed to remove interface", false);
   1227         } else {
   1228           cli->sendMsg(ResponseCode::CommandOkay, "Remove success", false);
   1229         }
   1230         return 0;
   1231     }
   1232 
   1233     cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown idletimer cmd", false);
   1234     return 0;
   1235 }
   1236 
   1237 CommandListener::FirewallCmd::FirewallCmd() :
   1238     NetdCommand("firewall") {
   1239 }
   1240 
   1241 int CommandListener::FirewallCmd::sendGenericOkFail(SocketClient *cli, int cond) {
   1242     if (!cond) {
   1243         cli->sendMsg(ResponseCode::CommandOkay, "Firewall command succeeded", false);
   1244     } else {
   1245         cli->sendMsg(ResponseCode::OperationFailed, "Firewall command failed", false);
   1246     }
   1247     return 0;
   1248 }
   1249 
   1250 FirewallRule CommandListener::FirewallCmd::parseRule(const char* arg) {
   1251     if (!strcmp(arg, "allow")) {
   1252         return ALLOW;
   1253     } else if (!strcmp(arg, "deny")) {
   1254         return DENY;
   1255     } else {
   1256         ALOGE("failed to parse uid rule (%s)", arg);
   1257         return ALLOW;
   1258     }
   1259 }
   1260 
   1261 FirewallType CommandListener::FirewallCmd::parseFirewallType(const char* arg) {
   1262     if (!strcmp(arg, "whitelist")) {
   1263         return WHITELIST;
   1264     } else if (!strcmp(arg, "blacklist")) {
   1265         return BLACKLIST;
   1266     } else {
   1267         ALOGE("failed to parse firewall type (%s)", arg);
   1268         return BLACKLIST;
   1269     }
   1270 }
   1271 
   1272 ChildChain CommandListener::FirewallCmd::parseChildChain(const char* arg) {
   1273     if (!strcmp(arg, "dozable")) {
   1274         return DOZABLE;
   1275     } else if (!strcmp(arg, "standby")) {
   1276         return STANDBY;
   1277     } else if (!strcmp(arg, "powersave")) {
   1278         return POWERSAVE;
   1279     } else if (!strcmp(arg, "none")) {
   1280         return NONE;
   1281     } else {
   1282         ALOGE("failed to parse child firewall chain (%s)", arg);
   1283         return INVALID_CHAIN;
   1284     }
   1285 }
   1286 
   1287 int CommandListener::FirewallCmd::runCommand(SocketClient *cli, int argc,
   1288         char **argv) {
   1289     if (argc < 2) {
   1290         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing command", false);
   1291         return 0;
   1292     }
   1293 
   1294     if (!strcmp(argv[1], "enable")) {
   1295         if (argc != 3) {
   1296             cli->sendMsg(ResponseCode::CommandSyntaxError,
   1297                         "Usage: firewall enable <whitelist|blacklist>", false);
   1298             return 0;
   1299         }
   1300         FirewallType firewallType = parseFirewallType(argv[2]);
   1301 
   1302         int res = gCtls->firewallCtrl.enableFirewall(firewallType);
   1303         return sendGenericOkFail(cli, res);
   1304     }
   1305     if (!strcmp(argv[1], "disable")) {
   1306         int res = gCtls->firewallCtrl.disableFirewall();
   1307         return sendGenericOkFail(cli, res);
   1308     }
   1309     if (!strcmp(argv[1], "is_enabled")) {
   1310         int res = gCtls->firewallCtrl.isFirewallEnabled();
   1311         return sendGenericOkFail(cli, res);
   1312     }
   1313 
   1314     if (!strcmp(argv[1], "set_interface_rule")) {
   1315         if (argc != 4) {
   1316             cli->sendMsg(ResponseCode::CommandSyntaxError,
   1317                          "Usage: firewall set_interface_rule <rmnet0> <allow|deny>", false);
   1318             return 0;
   1319         }
   1320 
   1321         const char* iface = argv[2];
   1322         FirewallRule rule = parseRule(argv[3]);
   1323 
   1324         int res = gCtls->firewallCtrl.setInterfaceRule(iface, rule);
   1325         return sendGenericOkFail(cli, res);
   1326     }
   1327 
   1328     if (!strcmp(argv[1], "set_egress_source_rule")) {
   1329         if (argc != 4) {
   1330             cli->sendMsg(ResponseCode::CommandSyntaxError,
   1331                          "Usage: firewall set_egress_source_rule <192.168.0.1> <allow|deny>",
   1332                          false);
   1333             return 0;
   1334         }
   1335 
   1336         const char* addr = argv[2];
   1337         FirewallRule rule = parseRule(argv[3]);
   1338 
   1339         int res = gCtls->firewallCtrl.setEgressSourceRule(addr, rule);
   1340         return sendGenericOkFail(cli, res);
   1341     }
   1342 
   1343     if (!strcmp(argv[1], "set_egress_dest_rule")) {
   1344         if (argc != 5) {
   1345             cli->sendMsg(ResponseCode::CommandSyntaxError,
   1346                          "Usage: firewall set_egress_dest_rule <192.168.0.1> <80> <allow|deny>",
   1347                          false);
   1348             return 0;
   1349         }
   1350 
   1351         const char* addr = argv[2];
   1352         int port = atoi(argv[3]);
   1353         FirewallRule rule = parseRule(argv[4]);
   1354 
   1355         int res = 0;
   1356         res |= gCtls->firewallCtrl.setEgressDestRule(addr, PROTOCOL_TCP, port, rule);
   1357         res |= gCtls->firewallCtrl.setEgressDestRule(addr, PROTOCOL_UDP, port, rule);
   1358         return sendGenericOkFail(cli, res);
   1359     }
   1360 
   1361     if (!strcmp(argv[1], "set_uid_rule")) {
   1362         if (argc != 5) {
   1363             cli->sendMsg(ResponseCode::CommandSyntaxError,
   1364                          "Usage: firewall set_uid_rule <dozable|standby|none> <1000> <allow|deny>",
   1365                          false);
   1366             return 0;
   1367         }
   1368 
   1369         ChildChain childChain = parseChildChain(argv[2]);
   1370         if (childChain == INVALID_CHAIN) {
   1371             cli->sendMsg(ResponseCode::CommandSyntaxError,
   1372                          "Invalid chain name. Valid names are: <dozable|standby|none>",
   1373                          false);
   1374             return 0;
   1375         }
   1376         int uid = atoi(argv[3]);
   1377         FirewallRule rule = parseRule(argv[4]);
   1378         int res = gCtls->firewallCtrl.setUidRule(childChain, uid, rule);
   1379         return sendGenericOkFail(cli, res);
   1380     }
   1381 
   1382     if (!strcmp(argv[1], "enable_chain")) {
   1383         if (argc != 3) {
   1384             cli->sendMsg(ResponseCode::CommandSyntaxError,
   1385                          "Usage: firewall enable_chain <dozable|standby>",
   1386                          false);
   1387             return 0;
   1388         }
   1389 
   1390         ChildChain childChain = parseChildChain(argv[2]);
   1391         int res = gCtls->firewallCtrl.enableChildChains(childChain, true);
   1392         return sendGenericOkFail(cli, res);
   1393     }
   1394 
   1395     if (!strcmp(argv[1], "disable_chain")) {
   1396         if (argc != 3) {
   1397             cli->sendMsg(ResponseCode::CommandSyntaxError,
   1398                          "Usage: firewall disable_chain <dozable|standby>",
   1399                          false);
   1400             return 0;
   1401         }
   1402 
   1403         ChildChain childChain = parseChildChain(argv[2]);
   1404         int res = gCtls->firewallCtrl.enableChildChains(childChain, false);
   1405         return sendGenericOkFail(cli, res);
   1406     }
   1407 
   1408     cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown command", false);
   1409     return 0;
   1410 }
   1411 
   1412 CommandListener::ClatdCmd::ClatdCmd() : NetdCommand("clatd") {
   1413 }
   1414 
   1415 int CommandListener::ClatdCmd::runCommand(SocketClient *cli, int argc,
   1416                                                             char **argv) {
   1417     int rc = 0;
   1418     if (argc < 3) {
   1419         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
   1420         return 0;
   1421     }
   1422 
   1423     if (!strcmp(argv[1], "stop")) {
   1424         rc = gCtls->clatdCtrl.stopClatd(argv[2]);
   1425     } else if (!strcmp(argv[1], "status")) {
   1426         char *tmp = NULL;
   1427         asprintf(&tmp, "Clatd status: %s", (gCtls->clatdCtrl.isClatdStarted(argv[2]) ?
   1428                                             "started" : "stopped"));
   1429         cli->sendMsg(ResponseCode::ClatdStatusResult, tmp, false);
   1430         free(tmp);
   1431         return 0;
   1432     } else if (!strcmp(argv[1], "start")) {
   1433         rc = gCtls->clatdCtrl.startClatd(argv[2]);
   1434     } else {
   1435         cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown clatd cmd", false);
   1436         return 0;
   1437     }
   1438 
   1439     if (!rc) {
   1440         cli->sendMsg(ResponseCode::CommandOkay, "Clatd operation succeeded", false);
   1441     } else {
   1442         cli->sendMsg(ResponseCode::OperationFailed, "Clatd operation failed", false);
   1443     }
   1444 
   1445     return 0;
   1446 }
   1447 
   1448 CommandListener::StrictCmd::StrictCmd() :
   1449     NetdCommand("strict") {
   1450 }
   1451 
   1452 int CommandListener::StrictCmd::sendGenericOkFail(SocketClient *cli, int cond) {
   1453     if (!cond) {
   1454         cli->sendMsg(ResponseCode::CommandOkay, "Strict command succeeded", false);
   1455     } else {
   1456         cli->sendMsg(ResponseCode::OperationFailed, "Strict command failed", false);
   1457     }
   1458     return 0;
   1459 }
   1460 
   1461 StrictPenalty CommandListener::StrictCmd::parsePenalty(const char* arg) {
   1462     if (!strcmp(arg, "reject")) {
   1463         return REJECT;
   1464     } else if (!strcmp(arg, "log")) {
   1465         return LOG;
   1466     } else if (!strcmp(arg, "accept")) {
   1467         return ACCEPT;
   1468     } else {
   1469         return INVALID;
   1470     }
   1471 }
   1472 
   1473 int CommandListener::StrictCmd::runCommand(SocketClient *cli, int argc,
   1474         char **argv) {
   1475     if (argc < 2) {
   1476         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing command", false);
   1477         return 0;
   1478     }
   1479 
   1480     if (!strcmp(argv[1], "enable")) {
   1481         int res = gCtls->strictCtrl.enableStrict();
   1482         return sendGenericOkFail(cli, res);
   1483     }
   1484     if (!strcmp(argv[1], "disable")) {
   1485         int res = gCtls->strictCtrl.disableStrict();
   1486         return sendGenericOkFail(cli, res);
   1487     }
   1488 
   1489     if (!strcmp(argv[1], "set_uid_cleartext_policy")) {
   1490         if (argc != 4) {
   1491             cli->sendMsg(ResponseCode::CommandSyntaxError,
   1492                          "Usage: strict set_uid_cleartext_policy <uid> <accept|log|reject>",
   1493                          false);
   1494             return 0;
   1495         }
   1496 
   1497         errno = 0;
   1498         unsigned long int uid = strtoul(argv[2], NULL, 0);
   1499         if (errno || uid > UID_MAX) {
   1500             cli->sendMsg(ResponseCode::CommandSyntaxError, "Invalid UID", false);
   1501             return 0;
   1502         }
   1503 
   1504         StrictPenalty penalty = parsePenalty(argv[3]);
   1505         if (penalty == INVALID) {
   1506             cli->sendMsg(ResponseCode::CommandSyntaxError, "Invalid penalty argument", false);
   1507             return 0;
   1508         }
   1509 
   1510         int res = gCtls->strictCtrl.setUidCleartextPenalty((uid_t) uid, penalty);
   1511         return sendGenericOkFail(cli, res);
   1512     }
   1513 
   1514     cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown command", false);
   1515     return 0;
   1516 }
   1517 
   1518 CommandListener::NetworkCommand::NetworkCommand() : NetdCommand("network") {
   1519 }
   1520 
   1521 int CommandListener::NetworkCommand::syntaxError(SocketClient* client, const char* message) {
   1522     client->sendMsg(ResponseCode::CommandSyntaxError, message, false);
   1523     return 0;
   1524 }
   1525 
   1526 int CommandListener::NetworkCommand::operationError(SocketClient* client, const char* message,
   1527                                                     int ret) {
   1528     errno = -ret;
   1529     client->sendMsg(ResponseCode::OperationFailed, message, true);
   1530     return 0;
   1531 }
   1532 
   1533 int CommandListener::NetworkCommand::success(SocketClient* client) {
   1534     client->sendMsg(ResponseCode::CommandOkay, "success", false);
   1535     return 0;
   1536 }
   1537 
   1538 int CommandListener::NetworkCommand::runCommand(SocketClient* client, int argc, char** argv) {
   1539     if (argc < 2) {
   1540         return syntaxError(client, "Missing argument");
   1541     }
   1542 
   1543     //    0      1      2      3      4       5         6            7           8
   1544     // network route [legacy <uid>]  add   <netId> <interface> <destination> [nexthop]
   1545     // network route [legacy <uid>] remove <netId> <interface> <destination> [nexthop]
   1546     //
   1547     // nexthop may be either an IPv4/IPv6 address or one of "unreachable" or "throw".
   1548     if (!strcmp(argv[1], "route")) {
   1549         if (argc < 6 || argc > 9) {
   1550             return syntaxError(client, "Incorrect number of arguments");
   1551         }
   1552 
   1553         int nextArg = 2;
   1554         bool legacy = false;
   1555         uid_t uid = 0;
   1556         if (!strcmp(argv[nextArg], "legacy")) {
   1557             ++nextArg;
   1558             legacy = true;
   1559             uid = strtoul(argv[nextArg++], NULL, 0);
   1560         }
   1561 
   1562         bool add = false;
   1563         if (!strcmp(argv[nextArg], "add")) {
   1564             add = true;
   1565         } else if (strcmp(argv[nextArg], "remove")) {
   1566             return syntaxError(client, "Unknown argument");
   1567         }
   1568         ++nextArg;
   1569 
   1570         if (argc < nextArg + 3 || argc > nextArg + 4) {
   1571             return syntaxError(client, "Incorrect number of arguments");
   1572         }
   1573 
   1574         unsigned netId = stringToNetId(argv[nextArg++]);
   1575         const char* interface = argv[nextArg++];
   1576         const char* destination = argv[nextArg++];
   1577         const char* nexthop = argc > nextArg ? argv[nextArg] : NULL;
   1578 
   1579         int ret;
   1580         if (add) {
   1581             ret = gCtls->netCtrl.addRoute(netId, interface, destination, nexthop, legacy, uid);
   1582         } else {
   1583             ret = gCtls->netCtrl.removeRoute(netId, interface, destination, nexthop, legacy, uid);
   1584         }
   1585         if (ret) {
   1586             return operationError(client, add ? "addRoute() failed" : "removeRoute() failed", ret);
   1587         }
   1588 
   1589         return success(client);
   1590     }
   1591 
   1592     //    0        1       2       3         4
   1593     // network interface  add   <netId> <interface>
   1594     // network interface remove <netId> <interface>
   1595     if (!strcmp(argv[1], "interface")) {
   1596         if (argc != 5) {
   1597             return syntaxError(client, "Missing argument");
   1598         }
   1599         unsigned netId = stringToNetId(argv[3]);
   1600         if (!strcmp(argv[2], "add")) {
   1601             if (int ret = gCtls->netCtrl.addInterfaceToNetwork(netId, argv[4])) {
   1602                 return operationError(client, "addInterfaceToNetwork() failed", ret);
   1603             }
   1604         } else if (!strcmp(argv[2], "remove")) {
   1605             if (int ret = gCtls->netCtrl.removeInterfaceFromNetwork(netId, argv[4])) {
   1606                 return operationError(client, "removeInterfaceFromNetwork() failed", ret);
   1607             }
   1608         } else {
   1609             return syntaxError(client, "Unknown argument");
   1610         }
   1611         return success(client);
   1612     }
   1613 
   1614     //    0      1       2         3
   1615     // network create <netId> [permission]
   1616     //
   1617     //    0      1       2     3     4        5
   1618     // network create <netId> vpn <hasDns> <secure>
   1619     if (!strcmp(argv[1], "create")) {
   1620         if (argc < 3) {
   1621             return syntaxError(client, "Missing argument");
   1622         }
   1623         unsigned netId = stringToNetId(argv[2]);
   1624         if (argc == 6 && !strcmp(argv[3], "vpn")) {
   1625             bool hasDns = atoi(argv[4]);
   1626             bool secure = atoi(argv[5]);
   1627             if (int ret = gCtls->netCtrl.createVirtualNetwork(netId, hasDns, secure)) {
   1628                 return operationError(client, "createVirtualNetwork() failed", ret);
   1629             }
   1630         } else if (argc > 4) {
   1631             return syntaxError(client, "Unknown trailing argument(s)");
   1632         } else {
   1633             Permission permission = PERMISSION_NONE;
   1634             if (argc == 4) {
   1635                 permission = stringToPermission(argv[3]);
   1636                 if (permission == PERMISSION_NONE) {
   1637                     return syntaxError(client, "Unknown permission");
   1638                 }
   1639             }
   1640             if (int ret = gCtls->netCtrl.createPhysicalNetwork(netId, permission)) {
   1641                 return operationError(client, "createPhysicalNetwork() failed", ret);
   1642             }
   1643         }
   1644         return success(client);
   1645     }
   1646 
   1647     //    0       1       2
   1648     // network destroy <netId>
   1649     if (!strcmp(argv[1], "destroy")) {
   1650         if (argc != 3) {
   1651             return syntaxError(client, "Incorrect number of arguments");
   1652         }
   1653         unsigned netId = stringToNetId(argv[2]);
   1654         if (int ret = gCtls->netCtrl.destroyNetwork(netId)) {
   1655             return operationError(client, "destroyNetwork() failed", ret);
   1656         }
   1657         return success(client);
   1658     }
   1659 
   1660     //    0       1      2      3
   1661     // network default  set  <netId>
   1662     // network default clear
   1663     if (!strcmp(argv[1], "default")) {
   1664         if (argc < 3) {
   1665             return syntaxError(client, "Missing argument");
   1666         }
   1667         unsigned netId = NETID_UNSET;
   1668         if (!strcmp(argv[2], "set")) {
   1669             if (argc < 4) {
   1670                 return syntaxError(client, "Missing netId");
   1671             }
   1672             netId = stringToNetId(argv[3]);
   1673         } else if (strcmp(argv[2], "clear")) {
   1674             return syntaxError(client, "Unknown argument");
   1675         }
   1676         if (int ret = gCtls->netCtrl.setDefaultNetwork(netId)) {
   1677             return operationError(client, "setDefaultNetwork() failed", ret);
   1678         }
   1679         return success(client);
   1680     }
   1681 
   1682     //    0        1         2      3        4          5
   1683     // network permission   user   set  <permission>  <uid> ...
   1684     // network permission   user  clear    <uid> ...
   1685     // network permission network  set  <permission> <netId> ...
   1686     // network permission network clear   <netId> ...
   1687     if (!strcmp(argv[1], "permission")) {
   1688         if (argc < 5) {
   1689             return syntaxError(client, "Missing argument");
   1690         }
   1691         int nextArg = 4;
   1692         Permission permission = PERMISSION_NONE;
   1693         if (!strcmp(argv[3], "set")) {
   1694             permission = stringToPermission(argv[4]);
   1695             if (permission == PERMISSION_NONE) {
   1696                 return syntaxError(client, "Unknown permission");
   1697             }
   1698             nextArg = 5;
   1699         } else if (strcmp(argv[3], "clear")) {
   1700             return syntaxError(client, "Unknown argument");
   1701         }
   1702         if (nextArg == argc) {
   1703             return syntaxError(client, "Missing id");
   1704         }
   1705 
   1706         bool userPermissions = !strcmp(argv[2], "user");
   1707         bool networkPermissions = !strcmp(argv[2], "network");
   1708         if (!userPermissions && !networkPermissions) {
   1709             return syntaxError(client, "Unknown argument");
   1710         }
   1711 
   1712         std::vector<unsigned> ids;
   1713         for (; nextArg < argc; ++nextArg) {
   1714             if (userPermissions) {
   1715                 char* endPtr;
   1716                 unsigned id = strtoul(argv[nextArg], &endPtr, 0);
   1717                 if (!*argv[nextArg] || *endPtr) {
   1718                     return syntaxError(client, "Invalid id");
   1719                 }
   1720                 ids.push_back(id);
   1721             } else {
   1722                 // networkPermissions
   1723                 ids.push_back(stringToNetId(argv[nextArg]));
   1724             }
   1725         }
   1726         if (userPermissions) {
   1727             gCtls->netCtrl.setPermissionForUsers(permission, ids);
   1728         } else {
   1729             // networkPermissions
   1730             if (int ret = gCtls->netCtrl.setPermissionForNetworks(permission, ids)) {
   1731                 return operationError(client, "setPermissionForNetworks() failed", ret);
   1732             }
   1733         }
   1734 
   1735         return success(client);
   1736     }
   1737 
   1738     //    0      1     2       3           4
   1739     // network users  add   <netId> [<uid>[-<uid>]] ...
   1740     // network users remove <netId> [<uid>[-<uid>]] ...
   1741     if (!strcmp(argv[1], "users")) {
   1742         if (argc < 4) {
   1743             return syntaxError(client, "Missing argument");
   1744         }
   1745         unsigned netId = stringToNetId(argv[3]);
   1746         UidRanges uidRanges;
   1747         if (!uidRanges.parseFrom(argc - 4, argv + 4)) {
   1748             return syntaxError(client, "Invalid UIDs");
   1749         }
   1750         if (!strcmp(argv[2], "add")) {
   1751             if (int ret = gCtls->netCtrl.addUsersToNetwork(netId, uidRanges)) {
   1752                 return operationError(client, "addUsersToNetwork() failed", ret);
   1753             }
   1754         } else if (!strcmp(argv[2], "remove")) {
   1755             if (int ret = gCtls->netCtrl.removeUsersFromNetwork(netId, uidRanges)) {
   1756                 return operationError(client, "removeUsersFromNetwork() failed", ret);
   1757             }
   1758         } else {
   1759             return syntaxError(client, "Unknown argument");
   1760         }
   1761         return success(client);
   1762     }
   1763 
   1764     //    0       1      2     3
   1765     // network protect allow <uid> ...
   1766     // network protect  deny <uid> ...
   1767     if (!strcmp(argv[1], "protect")) {
   1768         if (argc < 4) {
   1769             return syntaxError(client, "Missing argument");
   1770         }
   1771         std::vector<uid_t> uids;
   1772         for (int i = 3; i < argc; ++i) {
   1773             uids.push_back(strtoul(argv[i], NULL, 0));
   1774         }
   1775         if (!strcmp(argv[2], "allow")) {
   1776             gCtls->netCtrl.allowProtect(uids);
   1777         } else if (!strcmp(argv[2], "deny")) {
   1778             gCtls->netCtrl.denyProtect(uids);
   1779         } else {
   1780             return syntaxError(client, "Unknown argument");
   1781         }
   1782         return success(client);
   1783     }
   1784 
   1785     return syntaxError(client, "Unknown argument");
   1786 }
   1787