CommandListener.cpp revision 9caaa44f635f86200e2b9b4cd36d1471ce910a6a
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 <fcntl.h>
28#include <linux/if.h>
29
30#define LOG_TAG "CommandListener"
31
32#include <cutils/log.h>
33#include <netutils/ifc.h>
34#include <sysutils/SocketClient.h>
35
36#include "CommandListener.h"
37#include "ResponseCode.h"
38#include "ThrottleController.h"
39#include "BandwidthController.h"
40#include "IdletimerController.h"
41#include "SecondaryTableController.h"
42#include "oem_iptables_hook.h"
43#include "NetdConstants.h"
44
45TetherController *CommandListener::sTetherCtrl = NULL;
46NatController *CommandListener::sNatCtrl = NULL;
47PppController *CommandListener::sPppCtrl = NULL;
48PanController *CommandListener::sPanCtrl = NULL;
49SoftapController *CommandListener::sSoftapCtrl = NULL;
50BandwidthController * CommandListener::sBandwidthCtrl = NULL;
51IdletimerController * CommandListener::sIdletimerCtrl = NULL;
52ResolverController *CommandListener::sResolverCtrl = NULL;
53SecondaryTableController *CommandListener::sSecondaryTableCtrl = NULL;
54
55/**
56 * List of module chains to be created, along with explicit ordering. ORDERING
57 * IS CRITICAL, AND SHOULD BE TRIPLE-CHECKED WITH EACH CHANGE.
58 */
59static const char* FILTER_INPUT[] = {
60        BandwidthController::LOCAL_INPUT,
61        NULL,
62};
63
64static const char* FILTER_FORWARD[] = {
65        OEM_IPTABLES_FILTER_FORWARD,
66        BandwidthController::LOCAL_FORWARD,
67        NatController::LOCAL_FORWARD,
68        NULL,
69};
70
71static const char* FILTER_OUTPUT[] = {
72        OEM_IPTABLES_FILTER_OUTPUT,
73        BandwidthController::LOCAL_OUTPUT,
74        NULL,
75};
76
77static const char* RAW_PREROUTING[] = {
78        BandwidthController::LOCAL_RAW_PREROUTING,
79        NULL,
80};
81
82static const char* MANGLE_POSTROUTING[] = {
83        BandwidthController::LOCAL_MANGLE_POSTROUTING,
84        NULL,
85};
86
87static const char* NAT_PREROUTING[] = {
88        OEM_IPTABLES_NAT_PREROUTING,
89        IdletimerController::LOCAL_NAT_PREROUTING,
90        NULL,
91};
92
93static const char* NAT_POSTROUTING[] = {
94        IdletimerController::LOCAL_NAT_POSTROUTING,
95        NatController::LOCAL_NAT_POSTROUTING,
96        NULL,
97};
98
99static void createChildChains(IptablesTarget target, const char* table, const char* parentChain,
100        const char** childChains) {
101    const char** childChain = childChains;
102    do {
103        // Order is important:
104        // -D to delete any pre-existing jump rule (removes references
105        //    that would prevent -X from working)
106        // -F to flush any existing chain
107        // -X to delete any existing chain
108        // -N to create the chain
109        // -A to append the chain to parent
110
111        execIptablesSilently(target, "-t", table, "-D", parentChain, "-j", *childChain, NULL);
112        execIptablesSilently(target, "-t", table, "-F", *childChain, NULL);
113        execIptablesSilently(target, "-t", table, "-X", *childChain, NULL);
114        execIptables(target, "-t", table, "-N", *childChain, NULL);
115        execIptables(target, "-t", table, "-A", parentChain, "-j", *childChain, NULL);
116    } while (*(++childChain) != NULL);
117}
118
119CommandListener::CommandListener() :
120                 FrameworkListener("netd", true) {
121    registerCmd(new InterfaceCmd());
122    registerCmd(new IpFwdCmd());
123    registerCmd(new TetherCmd());
124    registerCmd(new NatCmd());
125    registerCmd(new ListTtysCmd());
126    registerCmd(new PppdCmd());
127    registerCmd(new PanCmd());
128    registerCmd(new SoftapCmd());
129    registerCmd(new BandwidthControlCmd());
130    registerCmd(new IdletimerControlCmd());
131    registerCmd(new ResolverCmd());
132
133    if (!sSecondaryTableCtrl)
134        sSecondaryTableCtrl = new SecondaryTableController();
135    if (!sTetherCtrl)
136        sTetherCtrl = new TetherController();
137    if (!sNatCtrl)
138        sNatCtrl = new NatController(sSecondaryTableCtrl);
139    if (!sPppCtrl)
140        sPppCtrl = new PppController();
141    if (!sPanCtrl)
142        sPanCtrl = new PanController();
143    if (!sSoftapCtrl)
144        sSoftapCtrl = new SoftapController();
145    if (!sBandwidthCtrl)
146        sBandwidthCtrl = new BandwidthController();
147    if (!sIdletimerCtrl)
148        sIdletimerCtrl = new IdletimerController();
149    if (!sResolverCtrl)
150        sResolverCtrl = new ResolverController();
151
152    /*
153     * This is the only time we touch top-level chains in iptables; controllers
154     * should only mutate rules inside of their children chains, as created by
155     * the constants above.
156     *
157     * Modules should never ACCEPT packets (except in well-justified cases);
158     * they should instead defer to any remaining modules using RETURN, or
159     * otherwise DROP/REJECT.
160     */
161
162    // Create chains for children modules
163    createChildChains(V4V6, "filter", "INPUT", FILTER_INPUT);
164    createChildChains(V4V6, "filter", "FORWARD", FILTER_FORWARD);
165    createChildChains(V4V6, "filter", "OUTPUT", FILTER_OUTPUT);
166    createChildChains(V4V6, "raw", "PREROUTING", RAW_PREROUTING);
167    createChildChains(V4V6, "mangle", "POSTROUTING", MANGLE_POSTROUTING);
168    createChildChains(V4, "nat", "PREROUTING", NAT_PREROUTING);
169    createChildChains(V4, "nat", "POSTROUTING", NAT_POSTROUTING);
170
171    // Let each module setup their child chains
172    setupOemIptablesHook();
173
174    /* Does DROPs in FORWARD by default */
175    sNatCtrl->setupIptablesHooks();
176    /*
177     * Does REJECT in INPUT, OUTPUT. Does counting also.
178     * No DROP/REJECT allowed later in netfilter-flow hook order.
179     */
180    sBandwidthCtrl->setupIptablesHooks();
181    /*
182     * Counts in nat: PREROUTING, POSTROUTING.
183     * No DROP/REJECT allowed later in netfilter-flow hook order.
184     */
185    sIdletimerCtrl->setupIptablesHooks();
186
187    sBandwidthCtrl->enableBandwidthControl(false);
188}
189
190CommandListener::InterfaceCmd::InterfaceCmd() :
191                 NetdCommand("interface") {
192}
193
194int CommandListener::writeFile(const char *path, const char *value, int size) {
195    int fd = open(path, O_WRONLY);
196    if (fd < 0) {
197        ALOGE("Failed to open %s: %s", path, strerror(errno));
198        return -1;
199    }
200
201    if (write(fd, value, size) != size) {
202        ALOGE("Failed to write %s: %s", path, strerror(errno));
203        close(fd);
204        return -1;
205    }
206    close(fd);
207    return 0;
208}
209
210int CommandListener::InterfaceCmd::runCommand(SocketClient *cli,
211                                                      int argc, char **argv) {
212    if (argc < 2) {
213        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
214        return 0;
215    }
216
217    if (!strcmp(argv[1], "list")) {
218        DIR *d;
219        struct dirent *de;
220
221        if (!(d = opendir("/sys/class/net"))) {
222            cli->sendMsg(ResponseCode::OperationFailed, "Failed to open sysfs dir", true);
223            return 0;
224        }
225
226        while((de = readdir(d))) {
227            if (de->d_name[0] == '.')
228                continue;
229            cli->sendMsg(ResponseCode::InterfaceListResult, de->d_name, false);
230        }
231        closedir(d);
232        cli->sendMsg(ResponseCode::CommandOkay, "Interface list completed", false);
233        return 0;
234    } else if (!strcmp(argv[1], "readrxcounter")) {
235        if (argc != 3) {
236            cli->sendMsg(ResponseCode::CommandSyntaxError,
237                    "Usage: interface readrxcounter <interface>", false);
238            return 0;
239        }
240        unsigned long rx = 0, tx = 0;
241        if (readInterfaceCounters(argv[2], &rx, &tx)) {
242            cli->sendMsg(ResponseCode::OperationFailed, "Failed to read counters", true);
243            return 0;
244        }
245
246        char *msg;
247        asprintf(&msg, "%lu", rx);
248        cli->sendMsg(ResponseCode::InterfaceRxCounterResult, msg, false);
249        free(msg);
250
251        return 0;
252    } else if (!strcmp(argv[1], "readtxcounter")) {
253        if (argc != 3) {
254            cli->sendMsg(ResponseCode::CommandSyntaxError,
255                    "Usage: interface readtxcounter <interface>", false);
256            return 0;
257        }
258        unsigned long rx = 0, tx = 0;
259        if (readInterfaceCounters(argv[2], &rx, &tx)) {
260            cli->sendMsg(ResponseCode::OperationFailed, "Failed to read counters", true);
261            return 0;
262        }
263
264        char *msg = NULL;
265        asprintf(&msg, "%lu", tx);
266        cli->sendMsg(ResponseCode::InterfaceTxCounterResult, msg, false);
267        free(msg);
268        return 0;
269    } else if (!strcmp(argv[1], "getthrottle")) {
270        if (argc != 4 || (argc == 4 && (strcmp(argv[3], "rx") && (strcmp(argv[3], "tx"))))) {
271            cli->sendMsg(ResponseCode::CommandSyntaxError,
272                    "Usage: interface getthrottle <interface> <rx|tx>", false);
273            return 0;
274        }
275        int val = 0;
276        int rc = 0;
277        int voldRc = ResponseCode::InterfaceRxThrottleResult;
278
279        if (!strcmp(argv[3], "rx")) {
280            rc = ThrottleController::getInterfaceRxThrottle(argv[2], &val);
281        } else {
282            rc = ThrottleController::getInterfaceTxThrottle(argv[2], &val);
283            voldRc = ResponseCode::InterfaceTxThrottleResult;
284        }
285        if (rc) {
286            cli->sendMsg(ResponseCode::OperationFailed, "Failed to get throttle", true);
287        } else {
288            char *msg = NULL;
289            asprintf(&msg, "%u", val);
290            cli->sendMsg(voldRc, msg, false);
291            free(msg);
292            return 0;
293        }
294        return 0;
295    } else if (!strcmp(argv[1], "setthrottle")) {
296        if (argc != 5) {
297            cli->sendMsg(ResponseCode::CommandSyntaxError,
298                    "Usage: interface setthrottle <interface> <rx_kbps> <tx_kbps>", false);
299            return 0;
300        }
301        if (ThrottleController::setInterfaceThrottle(argv[2], atoi(argv[3]), atoi(argv[4]))) {
302            cli->sendMsg(ResponseCode::OperationFailed, "Failed to set throttle", true);
303        } else {
304            cli->sendMsg(ResponseCode::CommandOkay, "Interface throttling set", false);
305        }
306        return 0;
307    } else {
308        /*
309         * These commands take a minimum of 3 arguments
310         */
311        if (argc < 3) {
312            cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
313            return 0;
314        }
315
316        //     0       1       2        3          4           5     6      7
317        // interface route add/remove iface default/secondary dest prefix gateway
318        if (!strcmp(argv[1], "route")) {
319            int prefix_length = 0;
320            if (argc < 8) {
321                cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
322                return 0;
323            }
324            if (sscanf(argv[6], "%d", &prefix_length) != 1) {
325                cli->sendMsg(ResponseCode::CommandParameterError, "Invalid route prefix", false);
326                return 0;
327            }
328            if (!strcmp(argv[2], "add")) {
329                if (!strcmp(argv[4], "default")) {
330                    if (ifc_add_route(argv[3], argv[5], prefix_length, argv[7])) {
331                        cli->sendMsg(ResponseCode::OperationFailed,
332                                "Failed to add route to default table", true);
333                    } else {
334                        cli->sendMsg(ResponseCode::CommandOkay,
335                                "Route added to default table", false);
336                    }
337                } else if (!strcmp(argv[4], "secondary")) {
338                    return sSecondaryTableCtrl->addRoute(cli, argv[3], argv[5],
339                            prefix_length, argv[7]);
340                } else {
341                    cli->sendMsg(ResponseCode::CommandParameterError,
342                            "Invalid route type, expecting 'default' or 'secondary'", false);
343                    return 0;
344                }
345            } else if (!strcmp(argv[2], "remove")) {
346                if (!strcmp(argv[4], "default")) {
347                    if (ifc_remove_route(argv[3], argv[5], prefix_length, argv[7])) {
348                        cli->sendMsg(ResponseCode::OperationFailed,
349                                "Failed to remove route from default table", true);
350                    } else {
351                        cli->sendMsg(ResponseCode::CommandOkay,
352                                "Route removed from default table", false);
353                    }
354                } else if (!strcmp(argv[4], "secondary")) {
355                    return sSecondaryTableCtrl->removeRoute(cli, argv[3], argv[5],
356                            prefix_length, argv[7]);
357                } else {
358                    cli->sendMsg(ResponseCode::CommandParameterError,
359                            "Invalid route type, expecting 'default' or 'secondary'", false);
360                    return 0;
361                }
362            } else {
363                cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown interface cmd", false);
364            }
365            return 0;
366        }
367
368        if (!strcmp(argv[1], "getcfg")) {
369            struct in_addr addr;
370            int prefixLength;
371            unsigned char hwaddr[6];
372            unsigned flags = 0;
373
374            ifc_init();
375            memset(hwaddr, 0, sizeof(hwaddr));
376
377            if (ifc_get_info(argv[2], &addr.s_addr, &prefixLength, &flags)) {
378                cli->sendMsg(ResponseCode::OperationFailed, "Interface not found", true);
379                ifc_close();
380                return 0;
381            }
382
383            if (ifc_get_hwaddr(argv[2], (void *) hwaddr)) {
384                ALOGW("Failed to retrieve HW addr for %s (%s)", argv[2], strerror(errno));
385            }
386
387            char *addr_s = strdup(inet_ntoa(addr));
388            const char *updown, *brdcst, *loopbk, *ppp, *running, *multi;
389
390            updown =  (flags & IFF_UP)           ? "up" : "down";
391            brdcst =  (flags & IFF_BROADCAST)    ? " broadcast" : "";
392            loopbk =  (flags & IFF_LOOPBACK)     ? " loopback" : "";
393            ppp =     (flags & IFF_POINTOPOINT)  ? " point-to-point" : "";
394            running = (flags & IFF_RUNNING)      ? " running" : "";
395            multi =   (flags & IFF_MULTICAST)    ? " multicast" : "";
396
397            char *flag_s;
398
399            asprintf(&flag_s, "%s%s%s%s%s%s", updown, brdcst, loopbk, ppp, running, multi);
400
401            char *msg = NULL;
402            asprintf(&msg, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x %s %d %s",
403                     hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5],
404                     addr_s, prefixLength, flag_s);
405
406            cli->sendMsg(ResponseCode::InterfaceGetCfgResult, msg, false);
407
408            free(addr_s);
409            free(flag_s);
410            free(msg);
411
412            ifc_close();
413            return 0;
414        } else if (!strcmp(argv[1], "setcfg")) {
415            // arglist: iface [addr prefixLength] flags
416            if (argc < 4) {
417                cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
418                return 0;
419            }
420            ALOGD("Setting iface cfg");
421
422            struct in_addr addr;
423            unsigned flags = 0;
424            int index = 5;
425
426            ifc_init();
427
428            if (!inet_aton(argv[3], &addr)) {
429                // Handle flags only case
430                index = 3;
431            } else {
432                if (ifc_set_addr(argv[2], addr.s_addr)) {
433                    cli->sendMsg(ResponseCode::OperationFailed, "Failed to set address", true);
434                    ifc_close();
435                    return 0;
436                }
437
438                // Set prefix length on a non zero address
439                if (addr.s_addr != 0 && ifc_set_prefixLength(argv[2], atoi(argv[4]))) {
440                   cli->sendMsg(ResponseCode::OperationFailed, "Failed to set prefixLength", true);
441                   ifc_close();
442                   return 0;
443               }
444            }
445
446            /* Process flags */
447            for (int i = index; i < argc; i++) {
448                char *flag = argv[i];
449                if (!strcmp(flag, "up")) {
450                    ALOGD("Trying to bring up %s", argv[2]);
451                    if (ifc_up(argv[2])) {
452                        ALOGE("Error upping interface");
453                        cli->sendMsg(ResponseCode::OperationFailed, "Failed to up interface", true);
454                        ifc_close();
455                        return 0;
456                    }
457                } else if (!strcmp(flag, "down")) {
458                    ALOGD("Trying to bring down %s", argv[2]);
459                    if (ifc_down(argv[2])) {
460                        ALOGE("Error downing interface");
461                        cli->sendMsg(ResponseCode::OperationFailed, "Failed to down interface", true);
462                        ifc_close();
463                        return 0;
464                    }
465                } else if (!strcmp(flag, "broadcast")) {
466                    // currently ignored
467                } else if (!strcmp(flag, "multicast")) {
468                    // currently ignored
469                } else if (!strcmp(flag, "running")) {
470                    // currently ignored
471                } else if (!strcmp(flag, "loopback")) {
472                    // currently ignored
473                } else if (!strcmp(flag, "point-to-point")) {
474                    // currently ignored
475                } else {
476                    cli->sendMsg(ResponseCode::CommandParameterError, "Flag unsupported", false);
477                    ifc_close();
478                    return 0;
479                }
480            }
481
482            cli->sendMsg(ResponseCode::CommandOkay, "Interface configuration set", false);
483            ifc_close();
484            return 0;
485        } else if (!strcmp(argv[1], "clearaddrs")) {
486            // arglist: iface
487            ALOGD("Clearing all IP addresses on %s", argv[2]);
488
489            ifc_clear_addresses(argv[2]);
490
491            cli->sendMsg(ResponseCode::CommandOkay, "Interface IP addresses cleared", false);
492            return 0;
493        } else if (!strcmp(argv[1], "ipv6privacyextensions")) {
494            if (argc != 4) {
495                cli->sendMsg(ResponseCode::CommandSyntaxError,
496                        "Usage: interface ipv6privacyextensions <interface> <enable|disable>",
497                        false);
498                return 0;
499            }
500
501            char *tmp;
502            asprintf(&tmp, "/proc/sys/net/ipv6/conf/%s/use_tempaddr", argv[2]);
503
504            if (writeFile(tmp, !strncmp(argv[3], "enable", 7) ? "2" : "0", 1) < 0) {
505                free(tmp);
506                cli->sendMsg(ResponseCode::OperationFailed,
507                        "Failed to set ipv6 privacy extensions", true);
508                return 0;
509            }
510
511            free(tmp);
512            cli->sendMsg(ResponseCode::CommandOkay, "IPv6 privacy extensions changed", false);
513            return 0;
514        } else if (!strcmp(argv[1], "ipv6")) {
515            if (argc != 4) {
516                cli->sendMsg(ResponseCode::CommandSyntaxError,
517                        "Usage: interface ipv6 <interface> <enable|disable>",
518                        false);
519                return 0;
520            }
521
522            char *tmp;
523            asprintf(&tmp, "/proc/sys/net/ipv6/conf/%s/disable_ipv6", argv[2]);
524
525            if (writeFile(tmp, !strncmp(argv[3], "enable", 7) ? "0" : "1", 1) < 0) {
526                free(tmp);
527                cli->sendMsg(ResponseCode::OperationFailed,
528                        "Failed to change IPv6 state", true);
529                return 0;
530            }
531
532            free(tmp);
533            cli->sendMsg(ResponseCode::CommandOkay, "IPv6 state changed", false);
534            return 0;
535        } else {
536            cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown interface cmd", false);
537            return 0;
538        }
539    }
540    return 0;
541}
542
543
544CommandListener::ListTtysCmd::ListTtysCmd() :
545                 NetdCommand("list_ttys") {
546}
547
548int CommandListener::ListTtysCmd::runCommand(SocketClient *cli,
549                                             int argc, char **argv) {
550    TtyCollection *tlist = sPppCtrl->getTtyList();
551    TtyCollection::iterator it;
552
553    for (it = tlist->begin(); it != tlist->end(); ++it) {
554        cli->sendMsg(ResponseCode::TtyListResult, *it, false);
555    }
556
557    cli->sendMsg(ResponseCode::CommandOkay, "Ttys listed.", false);
558    return 0;
559}
560
561CommandListener::IpFwdCmd::IpFwdCmd() :
562                 NetdCommand("ipfwd") {
563}
564
565int CommandListener::IpFwdCmd::runCommand(SocketClient *cli,
566                                                      int argc, char **argv) {
567    int rc = 0;
568
569    if (argc < 2) {
570        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
571        return 0;
572    }
573
574    if (!strcmp(argv[1], "status")) {
575        char *tmp = NULL;
576
577        asprintf(&tmp, "Forwarding %s", (sTetherCtrl->getIpFwdEnabled() ? "enabled" : "disabled"));
578        cli->sendMsg(ResponseCode::IpFwdStatusResult, tmp, false);
579        free(tmp);
580        return 0;
581    } else if (!strcmp(argv[1], "enable")) {
582        rc = sTetherCtrl->setIpFwdEnabled(true);
583    } else if (!strcmp(argv[1], "disable")) {
584        rc = sTetherCtrl->setIpFwdEnabled(false);
585    } else {
586        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown ipfwd cmd", false);
587        return 0;
588    }
589
590    if (!rc) {
591        cli->sendMsg(ResponseCode::CommandOkay, "ipfwd operation succeeded", false);
592    } else {
593        cli->sendMsg(ResponseCode::OperationFailed, "ipfwd operation failed", true);
594    }
595
596    return 0;
597}
598
599CommandListener::TetherCmd::TetherCmd() :
600                 NetdCommand("tether") {
601}
602
603int CommandListener::TetherCmd::runCommand(SocketClient *cli,
604                                                      int argc, char **argv) {
605    int rc = 0;
606
607    if (argc < 2) {
608        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
609        return 0;
610    }
611
612    if (!strcmp(argv[1], "stop")) {
613        rc = sTetherCtrl->stopTethering();
614    } else if(!strcmp(argv[1], "start-reverse")) {
615        ALOGD("CommandListener::TetherCmd::run, call startReverseTethering, iface:%s", argv[2]);
616        sTetherCtrl->startReverseTethering(argv[2]);
617    } else if (!strcmp(argv[1], "stop-reverse")) {
618        ALOGD("CommandListener::TetherCmd::run, call stopReverseTethering");
619        rc = sTetherCtrl->stopReverseTethering();
620    } else if (!strcmp(argv[1], "status")) {
621        char *tmp = NULL;
622
623        asprintf(&tmp, "Tethering services %s",
624                 (sTetherCtrl->isTetheringStarted() ? "started" : "stopped"));
625        cli->sendMsg(ResponseCode::TetherStatusResult, tmp, false);
626        free(tmp);
627        return 0;
628    } else {
629        /*
630         * These commands take a minimum of 4 arguments
631         */
632        if (argc < 4) {
633            cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
634            return 0;
635        }
636
637        if (!strcmp(argv[1], "start")) {
638            if (argc % 2 == 1) {
639                cli->sendMsg(ResponseCode::CommandSyntaxError, "Bad number of arguments", false);
640                return 0;
641            }
642
643            int num_addrs = argc - 2;
644            int arg_index = 2;
645            int array_index = 0;
646            in_addr *addrs = (in_addr *)malloc(sizeof(in_addr) * num_addrs);
647            while (array_index < num_addrs) {
648                if (!inet_aton(argv[arg_index++], &(addrs[array_index++]))) {
649                    cli->sendMsg(ResponseCode::CommandParameterError, "Invalid address", false);
650                    free(addrs);
651                    return 0;
652                }
653            }
654            rc = sTetherCtrl->startTethering(num_addrs, addrs);
655            free(addrs);
656        } else if (!strcmp(argv[1], "interface")) {
657            if (!strcmp(argv[2], "add")) {
658                rc = sTetherCtrl->tetherInterface(argv[3]);
659            } else if (!strcmp(argv[2], "remove")) {
660                rc = sTetherCtrl->untetherInterface(argv[3]);
661            } else if (!strcmp(argv[2], "list")) {
662                InterfaceCollection *ilist = sTetherCtrl->getTetheredInterfaceList();
663                InterfaceCollection::iterator it;
664
665                for (it = ilist->begin(); it != ilist->end(); ++it) {
666                    cli->sendMsg(ResponseCode::TetherInterfaceListResult, *it, false);
667                }
668            } else {
669                cli->sendMsg(ResponseCode::CommandParameterError,
670                             "Unknown tether interface operation", false);
671                return 0;
672            }
673        } else if (!strcmp(argv[1], "dns")) {
674            if (!strcmp(argv[2], "set")) {
675                rc = sTetherCtrl->setDnsForwarders(&argv[3], argc - 3);
676            } else if (!strcmp(argv[2], "list")) {
677                NetAddressCollection *dlist = sTetherCtrl->getDnsForwarders();
678                NetAddressCollection::iterator it;
679
680                for (it = dlist->begin(); it != dlist->end(); ++it) {
681                    cli->sendMsg(ResponseCode::TetherDnsFwdTgtListResult, inet_ntoa(*it), false);
682                }
683            } else {
684                cli->sendMsg(ResponseCode::CommandParameterError,
685                             "Unknown tether interface operation", false);
686                return 0;
687            }
688        } else {
689            cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown tether cmd", false);
690            return 0;
691        }
692    }
693
694    if (!rc) {
695        cli->sendMsg(ResponseCode::CommandOkay, "Tether operation succeeded", false);
696    } else {
697        cli->sendMsg(ResponseCode::OperationFailed, "Tether operation failed", true);
698    }
699
700    return 0;
701}
702
703CommandListener::NatCmd::NatCmd() :
704                 NetdCommand("nat") {
705}
706
707int CommandListener::NatCmd::runCommand(SocketClient *cli,
708                                                      int argc, char **argv) {
709    int rc = 0;
710
711    if (argc < 5) {
712        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
713        return 0;
714    }
715
716    if (!strcmp(argv[1], "enable")) {
717        rc = sNatCtrl->enableNat(argc, argv);
718        if(!rc) {
719            /* Ignore ifaces for now. */
720            rc = sBandwidthCtrl->setGlobalAlertInForwardChain();
721        }
722    } else if (!strcmp(argv[1], "disable")) {
723        /* Ignore ifaces for now. */
724        rc = sBandwidthCtrl->removeGlobalAlertInForwardChain();
725        rc |= sNatCtrl->disableNat(argc, argv);
726    } else {
727        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown nat cmd", false);
728        return 0;
729    }
730
731    if (!rc) {
732        cli->sendMsg(ResponseCode::CommandOkay, "Nat operation succeeded", false);
733    } else {
734        cli->sendMsg(ResponseCode::OperationFailed, "Nat operation failed", true);
735    }
736
737    return 0;
738}
739
740CommandListener::PppdCmd::PppdCmd() :
741                 NetdCommand("pppd") {
742}
743
744int CommandListener::PppdCmd::runCommand(SocketClient *cli,
745                                                      int argc, char **argv) {
746    int rc = 0;
747
748    if (argc < 3) {
749        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
750        return 0;
751    }
752
753    if (!strcmp(argv[1], "attach")) {
754        struct in_addr l, r, dns1, dns2;
755
756        memset(&dns1, sizeof(struct in_addr), 0);
757        memset(&dns2, sizeof(struct in_addr), 0);
758
759        if (!inet_aton(argv[3], &l)) {
760            cli->sendMsg(ResponseCode::CommandParameterError, "Invalid local address", false);
761            return 0;
762        }
763        if (!inet_aton(argv[4], &r)) {
764            cli->sendMsg(ResponseCode::CommandParameterError, "Invalid remote address", false);
765            return 0;
766        }
767        if ((argc > 3) && (!inet_aton(argv[5], &dns1))) {
768            cli->sendMsg(ResponseCode::CommandParameterError, "Invalid dns1 address", false);
769            return 0;
770        }
771        if ((argc > 4) && (!inet_aton(argv[6], &dns2))) {
772            cli->sendMsg(ResponseCode::CommandParameterError, "Invalid dns2 address", false);
773            return 0;
774        }
775        rc = sPppCtrl->attachPppd(argv[2], l, r, dns1, dns2);
776    } else if (!strcmp(argv[1], "detach")) {
777        rc = sPppCtrl->detachPppd(argv[2]);
778    } else {
779        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown pppd cmd", false);
780        return 0;
781    }
782
783    if (!rc) {
784        cli->sendMsg(ResponseCode::CommandOkay, "Pppd operation succeeded", false);
785    } else {
786        cli->sendMsg(ResponseCode::OperationFailed, "Pppd operation failed", true);
787    }
788
789    return 0;
790}
791
792CommandListener::PanCmd::PanCmd() :
793                 NetdCommand("pan") {
794}
795
796int CommandListener::PanCmd::runCommand(SocketClient *cli,
797                                        int argc, char **argv) {
798    int rc = 0;
799
800    if (argc < 2) {
801        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
802        return 0;
803    }
804
805    if (!strcmp(argv[1], "start")) {
806        rc = sPanCtrl->startPan();
807    } else if (!strcmp(argv[1], "stop")) {
808        rc = sPanCtrl->stopPan();
809    } else if (!strcmp(argv[1], "status")) {
810        char *tmp = NULL;
811
812        asprintf(&tmp, "Pan services %s",
813                 (sPanCtrl->isPanStarted() ? "started" : "stopped"));
814        cli->sendMsg(ResponseCode::PanStatusResult, tmp, false);
815        free(tmp);
816        return 0;
817    } else {
818        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown pan cmd", false);
819        return 0;
820    }
821
822    if (!rc) {
823        cli->sendMsg(ResponseCode::CommandOkay, "Pan operation succeeded", false);
824    } else {
825        cli->sendMsg(ResponseCode::OperationFailed, "Pan operation failed", true);
826    }
827
828    return 0;
829}
830
831CommandListener::SoftapCmd::SoftapCmd() :
832                 NetdCommand("softap") {
833}
834
835int CommandListener::SoftapCmd::runCommand(SocketClient *cli,
836                                        int argc, char **argv) {
837    int rc = 0, flag = 0;
838    char *retbuf = NULL;
839
840    if (argc < 2) {
841        cli->sendMsg(ResponseCode::CommandSyntaxError, "Softap Missing argument", false);
842        return 0;
843    }
844
845    if (!strcmp(argv[1], "startap")) {
846        rc = sSoftapCtrl->startSoftap();
847    } else if (!strcmp(argv[1], "stopap")) {
848        rc = sSoftapCtrl->stopSoftap();
849    } else if (!strcmp(argv[1], "fwreload")) {
850        rc = sSoftapCtrl->fwReloadSoftap(argc, argv);
851    } else if (!strcmp(argv[1], "clients")) {
852        rc = sSoftapCtrl->clientsSoftap(&retbuf);
853        if (!rc) {
854            cli->sendMsg(ResponseCode::CommandOkay, retbuf, false);
855            free(retbuf);
856            return 0;
857        }
858    } else if (!strcmp(argv[1], "status")) {
859        asprintf(&retbuf, "Softap service %s",
860                 (sSoftapCtrl->isSoftapStarted() ? "started" : "stopped"));
861        cli->sendMsg(ResponseCode::SoftapStatusResult, retbuf, false);
862        free(retbuf);
863        return 0;
864    } else if (!strcmp(argv[1], "set")) {
865        rc = sSoftapCtrl->setSoftap(argc, argv);
866    } else {
867        cli->sendMsg(ResponseCode::CommandSyntaxError, "Softap Unknown cmd", false);
868        return 0;
869    }
870
871    if (!rc) {
872        cli->sendMsg(ResponseCode::CommandOkay, "Softap operation succeeded", false);
873    } else {
874        cli->sendMsg(ResponseCode::OperationFailed, "Softap operation failed", true);
875    }
876
877    return 0;
878}
879
880CommandListener::ResolverCmd::ResolverCmd() :
881        NetdCommand("resolver") {
882}
883
884int CommandListener::ResolverCmd::runCommand(SocketClient *cli, int argc, char **argv) {
885    int rc = 0;
886    struct in_addr addr;
887
888    if (argc < 2) {
889        cli->sendMsg(ResponseCode::CommandSyntaxError, "Resolver missing arguments", false);
890        return 0;
891    }
892
893    if (!strcmp(argv[1], "setdefaultif")) { // "resolver setdefaultif <iface>"
894        if (argc == 3) {
895            rc = sResolverCtrl->setDefaultInterface(argv[2]);
896        } else {
897            cli->sendMsg(ResponseCode::CommandSyntaxError,
898                    "Wrong number of arguments to resolver setdefaultif", false);
899            return 0;
900        }
901    } else if (!strcmp(argv[1], "setifdns")) { // "resolver setifdns <iface> <dns1> <dns2> ..."
902        if (argc >= 4) {
903            rc = sResolverCtrl->setInterfaceDnsServers(argv[2], &argv[3], argc - 3);
904        } else {
905            cli->sendMsg(ResponseCode::CommandSyntaxError,
906                    "Wrong number of arguments to resolver setifdns", false);
907            return 0;
908        }
909
910        // set the address of the interface to which the name servers
911        // are bound. Required in order to bind to right interface when
912        // doing the dns query.
913        if (!rc) {
914            ifc_init();
915            ifc_get_info(argv[2], &addr.s_addr, NULL, 0);
916
917            rc = sResolverCtrl->setInterfaceAddress(argv[2], &addr);
918        }
919    } else if (!strcmp(argv[1], "flushdefaultif")) { // "resolver flushdefaultif"
920        if (argc == 2) {
921            rc = sResolverCtrl->flushDefaultDnsCache();
922        } else {
923            cli->sendMsg(ResponseCode::CommandSyntaxError,
924                    "Wrong number of arguments to resolver flushdefaultif", false);
925            return 0;
926        }
927    } else if (!strcmp(argv[1], "flushif")) { // "resolver flushif <iface>"
928        if (argc == 3) {
929            rc = sResolverCtrl->flushInterfaceDnsCache(argv[2]);
930        } else {
931            cli->sendMsg(ResponseCode::CommandSyntaxError,
932                    "Wrong number of arguments to resolver setdefaultif", false);
933            return 0;
934        }
935    } else {
936        cli->sendMsg(ResponseCode::CommandSyntaxError,"Resolver unknown command", false);
937        return 0;
938    }
939
940    if (!rc) {
941        cli->sendMsg(ResponseCode::CommandOkay, "Resolver command succeeded", false);
942    } else {
943        cli->sendMsg(ResponseCode::OperationFailed, "Resolver command failed", true);
944    }
945
946    return 0;
947}
948
949int CommandListener::readInterfaceCounters(const char *iface, unsigned long *rx, unsigned long *tx) {
950    FILE *fp = fopen("/proc/net/dev", "r");
951    if (!fp) {
952        ALOGE("Failed to open /proc/net/dev (%s)", strerror(errno));
953        return -1;
954    }
955
956    char buffer[512];
957
958    fgets(buffer, sizeof(buffer), fp); // Header 1
959    fgets(buffer, sizeof(buffer), fp); // Header 2
960    while(fgets(buffer, sizeof(buffer), fp)) {
961        buffer[strlen(buffer)-1] = '\0';
962
963        char name[31];
964        unsigned long d;
965        sscanf(buffer, "%30s %lu %lu %lu %lu %lu %lu %lu %lu %lu",
966                name, rx, &d, &d, &d, &d, &d, &d, &d, tx);
967        char *rxString = strchr(name, ':');
968        *rxString = '\0';
969        rxString++;
970        // when the rx count gets too big it changes from "name: 999" to "name:1000"
971        // and the sscanf munge the two together.  Detect that and fix
972        // note that all the %lu will be off by one and the real tx value will be in d
973        if (*rxString != '\0') {
974            *tx = d;
975            sscanf(rxString, "%20lu", rx);
976        }
977        if (strcmp(name, iface)) {
978            continue;
979        }
980        fclose(fp);
981        return 0;
982    }
983
984    fclose(fp);
985    *rx = 0;
986    *tx = 0;
987    return 0;
988}
989
990CommandListener::BandwidthControlCmd::BandwidthControlCmd() :
991    NetdCommand("bandwidth") {
992}
993
994void CommandListener::BandwidthControlCmd::sendGenericSyntaxError(SocketClient *cli, const char *usageMsg) {
995    char *msg;
996    asprintf(&msg, "Usage: bandwidth %s", usageMsg);
997    cli->sendMsg(ResponseCode::CommandSyntaxError, msg, false);
998    free(msg);
999}
1000
1001void CommandListener::BandwidthControlCmd::sendGenericOkFail(SocketClient *cli, int cond) {
1002    if (!cond) {
1003        cli->sendMsg(ResponseCode::CommandOkay, "Bandwidth command succeeeded", false);
1004    } else {
1005        cli->sendMsg(ResponseCode::OperationFailed, "Bandwidth command failed", false);
1006    }
1007}
1008
1009void CommandListener::BandwidthControlCmd::sendGenericOpFailed(SocketClient *cli, const char *errMsg) {
1010    cli->sendMsg(ResponseCode::OperationFailed, errMsg, false);
1011}
1012
1013int CommandListener::BandwidthControlCmd::runCommand(SocketClient *cli, int argc, char **argv) {
1014    if (argc < 2) {
1015        sendGenericSyntaxError(cli, "<cmds> <args...>");
1016        return 0;
1017    }
1018
1019    ALOGV("bwctrlcmd: argc=%d %s %s ...", argc, argv[0], argv[1]);
1020
1021    if (!strcmp(argv[1], "enable")) {
1022        int rc = sBandwidthCtrl->enableBandwidthControl(true);
1023        sendGenericOkFail(cli, rc);
1024        return 0;
1025
1026    }
1027    if (!strcmp(argv[1], "disable")) {
1028        int rc = sBandwidthCtrl->disableBandwidthControl();
1029        sendGenericOkFail(cli, rc);
1030        return 0;
1031
1032    }
1033    if (!strcmp(argv[1], "removequota") || !strcmp(argv[1], "rq")) {
1034        if (argc != 3) {
1035            sendGenericSyntaxError(cli, "removequota <interface>");
1036            return 0;
1037        }
1038        int rc = sBandwidthCtrl->removeInterfaceSharedQuota(argv[2]);
1039        sendGenericOkFail(cli, rc);
1040        return 0;
1041
1042    }
1043    if (!strcmp(argv[1], "getquota") || !strcmp(argv[1], "gq")) {
1044        int64_t bytes;
1045        if (argc != 2) {
1046            sendGenericSyntaxError(cli, "getquota");
1047            return 0;
1048        }
1049        int rc = sBandwidthCtrl->getInterfaceSharedQuota(&bytes);
1050        if (rc) {
1051            sendGenericOpFailed(cli, "Failed to get quota");
1052            return 0;
1053        }
1054
1055        char *msg;
1056        asprintf(&msg, "%lld", bytes);
1057        cli->sendMsg(ResponseCode::QuotaCounterResult, msg, false);
1058        free(msg);
1059        return 0;
1060
1061    }
1062    if (!strcmp(argv[1], "getiquota") || !strcmp(argv[1], "giq")) {
1063        int64_t bytes;
1064        if (argc != 3) {
1065            sendGenericSyntaxError(cli, "getiquota <iface>");
1066            return 0;
1067        }
1068
1069        int rc = sBandwidthCtrl->getInterfaceQuota(argv[2], &bytes);
1070        if (rc) {
1071            sendGenericOpFailed(cli, "Failed to get quota");
1072            return 0;
1073        }
1074        char *msg;
1075        asprintf(&msg, "%lld", bytes);
1076        cli->sendMsg(ResponseCode::QuotaCounterResult, msg, false);
1077        free(msg);
1078        return 0;
1079
1080    }
1081    if (!strcmp(argv[1], "setquota") || !strcmp(argv[1], "sq")) {
1082        if (argc != 4) {
1083            sendGenericSyntaxError(cli, "setquota <interface> <bytes>");
1084            return 0;
1085        }
1086        int rc = sBandwidthCtrl->setInterfaceSharedQuota(argv[2], atoll(argv[3]));
1087        sendGenericOkFail(cli, rc);
1088        return 0;
1089    }
1090    if (!strcmp(argv[1], "setquotas") || !strcmp(argv[1], "sqs")) {
1091        int rc;
1092        if (argc < 4) {
1093            sendGenericSyntaxError(cli, "setquotas <bytes> <interface> ...");
1094            return 0;
1095        }
1096
1097        for (int q = 3; argc >= 4; q++, argc--) {
1098            rc = sBandwidthCtrl->setInterfaceSharedQuota(argv[q], atoll(argv[2]));
1099            if (rc) {
1100                char *msg;
1101                asprintf(&msg, "bandwidth setquotas %s %s failed", argv[2], argv[q]);
1102                cli->sendMsg(ResponseCode::OperationFailed,
1103                             msg, false);
1104                free(msg);
1105                return 0;
1106            }
1107        }
1108        sendGenericOkFail(cli, rc);
1109        return 0;
1110
1111    }
1112    if (!strcmp(argv[1], "removequotas") || !strcmp(argv[1], "rqs")) {
1113        int rc;
1114        if (argc < 3) {
1115            sendGenericSyntaxError(cli, "removequotas <interface> ...");
1116            return 0;
1117        }
1118
1119        for (int q = 2; argc >= 3; q++, argc--) {
1120            rc = sBandwidthCtrl->removeInterfaceSharedQuota(argv[q]);
1121            if (rc) {
1122                char *msg;
1123                asprintf(&msg, "bandwidth removequotas %s failed", argv[q]);
1124                cli->sendMsg(ResponseCode::OperationFailed,
1125                             msg, false);
1126                free(msg);
1127                return 0;
1128            }
1129        }
1130        sendGenericOkFail(cli, rc);
1131        return 0;
1132
1133    }
1134    if (!strcmp(argv[1], "removeiquota") || !strcmp(argv[1], "riq")) {
1135        if (argc != 3) {
1136            sendGenericSyntaxError(cli, "removeiquota <interface>");
1137            return 0;
1138        }
1139        int rc = sBandwidthCtrl->removeInterfaceQuota(argv[2]);
1140        sendGenericOkFail(cli, rc);
1141        return 0;
1142
1143    }
1144    if (!strcmp(argv[1], "setiquota") || !strcmp(argv[1], "siq")) {
1145        if (argc != 4) {
1146            sendGenericSyntaxError(cli, "setiquota <interface> <bytes>");
1147            return 0;
1148        }
1149        int rc = sBandwidthCtrl->setInterfaceQuota(argv[2], atoll(argv[3]));
1150        sendGenericOkFail(cli, rc);
1151        return 0;
1152
1153    }
1154    if (!strcmp(argv[1], "addnaughtyapps") || !strcmp(argv[1], "ana")) {
1155        if (argc < 3) {
1156            sendGenericSyntaxError(cli, "addnaughtyapps <appUid> ...");
1157            return 0;
1158        }
1159        int rc = sBandwidthCtrl->addNaughtyApps(argc - 2, argv + 2);
1160        sendGenericOkFail(cli, rc);
1161        return 0;
1162
1163
1164    }
1165    if (!strcmp(argv[1], "removenaughtyapps") || !strcmp(argv[1], "rna")) {
1166        if (argc < 3) {
1167            sendGenericSyntaxError(cli, "removenaughtyapps <appUid> ...");
1168            return 0;
1169        }
1170        int rc = sBandwidthCtrl->removeNaughtyApps(argc - 2, argv + 2);
1171        sendGenericOkFail(cli, rc);
1172        return 0;
1173
1174    }
1175    if (!strcmp(argv[1], "setglobalalert") || !strcmp(argv[1], "sga")) {
1176        if (argc != 3) {
1177            sendGenericSyntaxError(cli, "setglobalalert <bytes>");
1178            return 0;
1179        }
1180        int rc = sBandwidthCtrl->setGlobalAlert(atoll(argv[2]));
1181        sendGenericOkFail(cli, rc);
1182        return 0;
1183
1184    }
1185    if (!strcmp(argv[1], "debugsettetherglobalalert") || !strcmp(argv[1], "dstga")) {
1186        if (argc != 4) {
1187            sendGenericSyntaxError(cli, "debugsettetherglobalalert <interface0> <interface1>");
1188            return 0;
1189        }
1190        /* We ignore the interfaces for now. */
1191        int rc = sBandwidthCtrl->setGlobalAlertInForwardChain();
1192        sendGenericOkFail(cli, rc);
1193        return 0;
1194
1195    }
1196    if (!strcmp(argv[1], "removeglobalalert") || !strcmp(argv[1], "rga")) {
1197        if (argc != 2) {
1198            sendGenericSyntaxError(cli, "removeglobalalert");
1199            return 0;
1200        }
1201        int rc = sBandwidthCtrl->removeGlobalAlert();
1202        sendGenericOkFail(cli, rc);
1203        return 0;
1204
1205    }
1206    if (!strcmp(argv[1], "debugremovetetherglobalalert") || !strcmp(argv[1], "drtga")) {
1207        if (argc != 4) {
1208            sendGenericSyntaxError(cli, "debugremovetetherglobalalert <interface0> <interface1>");
1209            return 0;
1210        }
1211        /* We ignore the interfaces for now. */
1212        int rc = sBandwidthCtrl->removeGlobalAlertInForwardChain();
1213        sendGenericOkFail(cli, rc);
1214        return 0;
1215
1216    }
1217    if (!strcmp(argv[1], "setsharedalert") || !strcmp(argv[1], "ssa")) {
1218        if (argc != 3) {
1219            sendGenericSyntaxError(cli, "setsharedalert <bytes>");
1220            return 0;
1221        }
1222        int rc = sBandwidthCtrl->setSharedAlert(atoll(argv[2]));
1223        sendGenericOkFail(cli, rc);
1224        return 0;
1225
1226    }
1227    if (!strcmp(argv[1], "removesharedalert") || !strcmp(argv[1], "rsa")) {
1228        if (argc != 2) {
1229            sendGenericSyntaxError(cli, "removesharedalert");
1230            return 0;
1231        }
1232        int rc = sBandwidthCtrl->removeSharedAlert();
1233        sendGenericOkFail(cli, rc);
1234        return 0;
1235
1236    }
1237    if (!strcmp(argv[1], "setinterfacealert") || !strcmp(argv[1], "sia")) {
1238        if (argc != 4) {
1239            sendGenericSyntaxError(cli, "setinterfacealert <interface> <bytes>");
1240            return 0;
1241        }
1242        int rc = sBandwidthCtrl->setInterfaceAlert(argv[2], atoll(argv[3]));
1243        sendGenericOkFail(cli, rc);
1244        return 0;
1245
1246    }
1247    if (!strcmp(argv[1], "removeinterfacealert") || !strcmp(argv[1], "ria")) {
1248        if (argc != 3) {
1249            sendGenericSyntaxError(cli, "removeinterfacealert <interface>");
1250            return 0;
1251        }
1252        int rc = sBandwidthCtrl->removeInterfaceAlert(argv[2]);
1253        sendGenericOkFail(cli, rc);
1254        return 0;
1255
1256    }
1257    if (!strcmp(argv[1], "gettetherstats") || !strcmp(argv[1], "gts")) {
1258        BandwidthController::TetherStats tetherStats;
1259        std::string extraProcessingInfo = "";
1260        if (argc != 4) {
1261            sendGenericSyntaxError(cli, "gettetherstats <interface0> <interface1>");
1262            return 0;
1263        }
1264
1265        tetherStats.ifaceIn = argv[2];
1266        tetherStats.ifaceOut = argv[3];
1267        int rc = sBandwidthCtrl->getTetherStats(tetherStats, extraProcessingInfo);
1268        if (rc) {
1269                extraProcessingInfo.insert(0, "Failed to get tethering stats.\n");
1270                sendGenericOpFailed(cli, extraProcessingInfo.c_str());
1271            return 0;
1272        }
1273
1274        char *msg = tetherStats.getStatsLine();
1275        cli->sendMsg(ResponseCode::TetheringStatsResult, msg, false);
1276        free(msg);
1277        return 0;
1278
1279    }
1280
1281    cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown bandwidth cmd", false);
1282    return 0;
1283}
1284
1285CommandListener::IdletimerControlCmd::IdletimerControlCmd() :
1286    NetdCommand("idletimer") {
1287}
1288
1289int CommandListener::IdletimerControlCmd::runCommand(SocketClient *cli, int argc, char **argv) {
1290  // TODO(ashish): Change the error statements
1291    if (argc < 2) {
1292        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
1293        return 0;
1294    }
1295
1296    ALOGV("idletimerctrlcmd: argc=%d %s %s ...", argc, argv[0], argv[1]);
1297
1298    if (!strcmp(argv[1], "enable")) {
1299      if (0 != sIdletimerCtrl->enableIdletimerControl()) {
1300        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
1301      } else {
1302        cli->sendMsg(ResponseCode::CommandOkay, "Enable success", false);
1303      }
1304      return 0;
1305
1306    }
1307    if (!strcmp(argv[1], "disable")) {
1308      if (0 != sIdletimerCtrl->disableIdletimerControl()) {
1309        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
1310      } else {
1311        cli->sendMsg(ResponseCode::CommandOkay, "Disable success", false);
1312      }
1313      return 0;
1314    }
1315    if (!strcmp(argv[1], "add")) {
1316        if (argc != 5) {
1317            cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
1318            return 0;
1319        }
1320        if(0 != sIdletimerCtrl->addInterfaceIdletimer(
1321                                        argv[2], atoi(argv[3]), argv[4])) {
1322          cli->sendMsg(ResponseCode::OperationFailed, "Failed to add interface", false);
1323        } else {
1324          cli->sendMsg(ResponseCode::CommandOkay,  "Add success", false);
1325        }
1326        return 0;
1327    }
1328    if (!strcmp(argv[1], "remove")) {
1329        if (argc != 5) {
1330            cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
1331            return 0;
1332        }
1333        // ashish: fixme timeout
1334        if (0 != sIdletimerCtrl->removeInterfaceIdletimer(
1335                                        argv[2], atoi(argv[3]), argv[4])) {
1336          cli->sendMsg(ResponseCode::OperationFailed, "Failed to remove interface", false);
1337        } else {
1338          cli->sendMsg(ResponseCode::CommandOkay, "Remove success", false);
1339        }
1340        return 0;
1341    }
1342
1343    cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown idletimer cmd", false);
1344    return 0;
1345}
1346