CommandListener.cpp revision 8e188ed5c989ddcc07f0f5e9839493c22d17e7b6
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], "status")) {
615        char *tmp = NULL;
616
617        asprintf(&tmp, "Tethering services %s",
618                 (sTetherCtrl->isTetheringStarted() ? "started" : "stopped"));
619        cli->sendMsg(ResponseCode::TetherStatusResult, tmp, false);
620        free(tmp);
621        return 0;
622    } else {
623        /*
624         * These commands take a minimum of 4 arguments
625         */
626        if (argc < 4) {
627            cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
628            return 0;
629        }
630
631        if (!strcmp(argv[1], "start")) {
632            if (argc % 2 == 1) {
633                cli->sendMsg(ResponseCode::CommandSyntaxError, "Bad number of arguments", false);
634                return 0;
635            }
636
637            int num_addrs = argc - 2;
638            int arg_index = 2;
639            int array_index = 0;
640            in_addr *addrs = (in_addr *)malloc(sizeof(in_addr) * num_addrs);
641            while (array_index < num_addrs) {
642                if (!inet_aton(argv[arg_index++], &(addrs[array_index++]))) {
643                    cli->sendMsg(ResponseCode::CommandParameterError, "Invalid address", false);
644                    free(addrs);
645                    return 0;
646                }
647            }
648            rc = sTetherCtrl->startTethering(num_addrs, addrs);
649            free(addrs);
650        } else if (!strcmp(argv[1], "interface")) {
651            if (!strcmp(argv[2], "add")) {
652                rc = sTetherCtrl->tetherInterface(argv[3]);
653            } else if (!strcmp(argv[2], "remove")) {
654                rc = sTetherCtrl->untetherInterface(argv[3]);
655            } else if (!strcmp(argv[2], "list")) {
656                InterfaceCollection *ilist = sTetherCtrl->getTetheredInterfaceList();
657                InterfaceCollection::iterator it;
658
659                for (it = ilist->begin(); it != ilist->end(); ++it) {
660                    cli->sendMsg(ResponseCode::TetherInterfaceListResult, *it, false);
661                }
662            } else {
663                cli->sendMsg(ResponseCode::CommandParameterError,
664                             "Unknown tether interface operation", false);
665                return 0;
666            }
667        } else if (!strcmp(argv[1], "dns")) {
668            if (!strcmp(argv[2], "set")) {
669                rc = sTetherCtrl->setDnsForwarders(&argv[3], argc - 3);
670            } else if (!strcmp(argv[2], "list")) {
671                NetAddressCollection *dlist = sTetherCtrl->getDnsForwarders();
672                NetAddressCollection::iterator it;
673
674                for (it = dlist->begin(); it != dlist->end(); ++it) {
675                    cli->sendMsg(ResponseCode::TetherDnsFwdTgtListResult, inet_ntoa(*it), false);
676                }
677            } else {
678                cli->sendMsg(ResponseCode::CommandParameterError,
679                             "Unknown tether interface operation", false);
680                return 0;
681            }
682        } else {
683            cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown tether cmd", false);
684            return 0;
685        }
686    }
687
688    if (!rc) {
689        cli->sendMsg(ResponseCode::CommandOkay, "Tether operation succeeded", false);
690    } else {
691        cli->sendMsg(ResponseCode::OperationFailed, "Tether operation failed", true);
692    }
693
694    return 0;
695}
696
697CommandListener::NatCmd::NatCmd() :
698                 NetdCommand("nat") {
699}
700
701int CommandListener::NatCmd::runCommand(SocketClient *cli,
702                                                      int argc, char **argv) {
703    int rc = 0;
704
705    if (argc < 5) {
706        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
707        return 0;
708    }
709
710    if (!strcmp(argv[1], "enable")) {
711        rc = sNatCtrl->enableNat(argc, argv);
712        if(!rc) {
713            /* Ignore ifaces for now. */
714            rc = sBandwidthCtrl->setGlobalAlertInForwardChain();
715        }
716    } else if (!strcmp(argv[1], "disable")) {
717        /* Ignore ifaces for now. */
718        rc = sBandwidthCtrl->removeGlobalAlertInForwardChain();
719        rc |= sNatCtrl->disableNat(argc, argv);
720    } else {
721        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown nat cmd", false);
722        return 0;
723    }
724
725    if (!rc) {
726        cli->sendMsg(ResponseCode::CommandOkay, "Nat operation succeeded", false);
727    } else {
728        cli->sendMsg(ResponseCode::OperationFailed, "Nat operation failed", true);
729    }
730
731    return 0;
732}
733
734CommandListener::PppdCmd::PppdCmd() :
735                 NetdCommand("pppd") {
736}
737
738int CommandListener::PppdCmd::runCommand(SocketClient *cli,
739                                                      int argc, char **argv) {
740    int rc = 0;
741
742    if (argc < 3) {
743        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
744        return 0;
745    }
746
747    if (!strcmp(argv[1], "attach")) {
748        struct in_addr l, r, dns1, dns2;
749
750        memset(&dns1, sizeof(struct in_addr), 0);
751        memset(&dns2, sizeof(struct in_addr), 0);
752
753        if (!inet_aton(argv[3], &l)) {
754            cli->sendMsg(ResponseCode::CommandParameterError, "Invalid local address", false);
755            return 0;
756        }
757        if (!inet_aton(argv[4], &r)) {
758            cli->sendMsg(ResponseCode::CommandParameterError, "Invalid remote address", false);
759            return 0;
760        }
761        if ((argc > 3) && (!inet_aton(argv[5], &dns1))) {
762            cli->sendMsg(ResponseCode::CommandParameterError, "Invalid dns1 address", false);
763            return 0;
764        }
765        if ((argc > 4) && (!inet_aton(argv[6], &dns2))) {
766            cli->sendMsg(ResponseCode::CommandParameterError, "Invalid dns2 address", false);
767            return 0;
768        }
769        rc = sPppCtrl->attachPppd(argv[2], l, r, dns1, dns2);
770    } else if (!strcmp(argv[1], "detach")) {
771        rc = sPppCtrl->detachPppd(argv[2]);
772    } else {
773        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown pppd cmd", false);
774        return 0;
775    }
776
777    if (!rc) {
778        cli->sendMsg(ResponseCode::CommandOkay, "Pppd operation succeeded", false);
779    } else {
780        cli->sendMsg(ResponseCode::OperationFailed, "Pppd operation failed", true);
781    }
782
783    return 0;
784}
785
786CommandListener::PanCmd::PanCmd() :
787                 NetdCommand("pan") {
788}
789
790int CommandListener::PanCmd::runCommand(SocketClient *cli,
791                                        int argc, char **argv) {
792    int rc = 0;
793
794    if (argc < 2) {
795        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
796        return 0;
797    }
798
799    if (!strcmp(argv[1], "start")) {
800        rc = sPanCtrl->startPan();
801    } else if (!strcmp(argv[1], "stop")) {
802        rc = sPanCtrl->stopPan();
803    } else if (!strcmp(argv[1], "status")) {
804        char *tmp = NULL;
805
806        asprintf(&tmp, "Pan services %s",
807                 (sPanCtrl->isPanStarted() ? "started" : "stopped"));
808        cli->sendMsg(ResponseCode::PanStatusResult, tmp, false);
809        free(tmp);
810        return 0;
811    } else {
812        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown pan cmd", false);
813        return 0;
814    }
815
816    if (!rc) {
817        cli->sendMsg(ResponseCode::CommandOkay, "Pan operation succeeded", false);
818    } else {
819        cli->sendMsg(ResponseCode::OperationFailed, "Pan operation failed", true);
820    }
821
822    return 0;
823}
824
825CommandListener::SoftapCmd::SoftapCmd() :
826                 NetdCommand("softap") {
827}
828
829int CommandListener::SoftapCmd::runCommand(SocketClient *cli,
830                                        int argc, char **argv) {
831    int rc = 0, flag = 0;
832    char *retbuf = NULL;
833
834    if (argc < 2) {
835        cli->sendMsg(ResponseCode::CommandSyntaxError, "Softap Missing argument", false);
836        return 0;
837    }
838
839    if (!strcmp(argv[1], "startap")) {
840        rc = sSoftapCtrl->startSoftap();
841    } else if (!strcmp(argv[1], "stopap")) {
842        rc = sSoftapCtrl->stopSoftap();
843    } else if (!strcmp(argv[1], "fwreload")) {
844        rc = sSoftapCtrl->fwReloadSoftap(argc, argv);
845    } else if (!strcmp(argv[1], "clients")) {
846        rc = sSoftapCtrl->clientsSoftap(&retbuf);
847        if (!rc) {
848            cli->sendMsg(ResponseCode::CommandOkay, retbuf, false);
849            free(retbuf);
850            return 0;
851        }
852    } else if (!strcmp(argv[1], "status")) {
853        asprintf(&retbuf, "Softap service %s",
854                 (sSoftapCtrl->isSoftapStarted() ? "started" : "stopped"));
855        cli->sendMsg(ResponseCode::SoftapStatusResult, retbuf, false);
856        free(retbuf);
857        return 0;
858    } else if (!strcmp(argv[1], "set")) {
859        rc = sSoftapCtrl->setSoftap(argc, argv);
860    } else {
861        cli->sendMsg(ResponseCode::CommandSyntaxError, "Softap Unknown cmd", false);
862        return 0;
863    }
864
865    if (!rc) {
866        cli->sendMsg(ResponseCode::CommandOkay, "Softap operation succeeded", false);
867    } else {
868        cli->sendMsg(ResponseCode::OperationFailed, "Softap operation failed", true);
869    }
870
871    return 0;
872}
873
874CommandListener::ResolverCmd::ResolverCmd() :
875        NetdCommand("resolver") {
876}
877
878int CommandListener::ResolverCmd::runCommand(SocketClient *cli, int argc, char **argv) {
879    int rc = 0;
880    struct in_addr addr;
881
882    if (argc < 2) {
883        cli->sendMsg(ResponseCode::CommandSyntaxError, "Resolver missing arguments", false);
884        return 0;
885    }
886
887    if (!strcmp(argv[1], "setdefaultif")) { // "resolver setdefaultif <iface>"
888        if (argc == 3) {
889            rc = sResolverCtrl->setDefaultInterface(argv[2]);
890        } else {
891            cli->sendMsg(ResponseCode::CommandSyntaxError,
892                    "Wrong number of arguments to resolver setdefaultif", false);
893            return 0;
894        }
895    } else if (!strcmp(argv[1], "setifdns")) { // "resolver setifdns <iface> <dns1> <dns2> ..."
896        if (argc >= 4) {
897            rc = sResolverCtrl->setInterfaceDnsServers(argv[2], &argv[3], argc - 3);
898        } else {
899            cli->sendMsg(ResponseCode::CommandSyntaxError,
900                    "Wrong number of arguments to resolver setifdns", false);
901            return 0;
902        }
903
904        // set the address of the interface to which the name servers
905        // are bound. Required in order to bind to right interface when
906        // doing the dns query.
907        if (!rc) {
908            ifc_init();
909            ifc_get_info(argv[2], &addr.s_addr, NULL, 0);
910
911            rc = sResolverCtrl->setInterfaceAddress(argv[2], &addr);
912        }
913    } else if (!strcmp(argv[1], "flushdefaultif")) { // "resolver flushdefaultif"
914        if (argc == 2) {
915            rc = sResolverCtrl->flushDefaultDnsCache();
916        } else {
917            cli->sendMsg(ResponseCode::CommandSyntaxError,
918                    "Wrong number of arguments to resolver flushdefaultif", false);
919            return 0;
920        }
921    } else if (!strcmp(argv[1], "flushif")) { // "resolver flushif <iface>"
922        if (argc == 3) {
923            rc = sResolverCtrl->flushInterfaceDnsCache(argv[2]);
924        } else {
925            cli->sendMsg(ResponseCode::CommandSyntaxError,
926                    "Wrong number of arguments to resolver setdefaultif", false);
927            return 0;
928        }
929    } else {
930        cli->sendMsg(ResponseCode::CommandSyntaxError,"Resolver unknown command", false);
931        return 0;
932    }
933
934    if (!rc) {
935        cli->sendMsg(ResponseCode::CommandOkay, "Resolver command succeeded", false);
936    } else {
937        cli->sendMsg(ResponseCode::OperationFailed, "Resolver command failed", true);
938    }
939
940    return 0;
941}
942
943int CommandListener::readInterfaceCounters(const char *iface, unsigned long *rx, unsigned long *tx) {
944    FILE *fp = fopen("/proc/net/dev", "r");
945    if (!fp) {
946        ALOGE("Failed to open /proc/net/dev (%s)", strerror(errno));
947        return -1;
948    }
949
950    char buffer[512];
951
952    fgets(buffer, sizeof(buffer), fp); // Header 1
953    fgets(buffer, sizeof(buffer), fp); // Header 2
954    while(fgets(buffer, sizeof(buffer), fp)) {
955        buffer[strlen(buffer)-1] = '\0';
956
957        char name[31];
958        unsigned long d;
959        sscanf(buffer, "%30s %lu %lu %lu %lu %lu %lu %lu %lu %lu",
960                name, rx, &d, &d, &d, &d, &d, &d, &d, tx);
961        char *rxString = strchr(name, ':');
962        *rxString = '\0';
963        rxString++;
964        // when the rx count gets too big it changes from "name: 999" to "name:1000"
965        // and the sscanf munge the two together.  Detect that and fix
966        // note that all the %lu will be off by one and the real tx value will be in d
967        if (*rxString != '\0') {
968            *tx = d;
969            sscanf(rxString, "%20lu", rx);
970        }
971        if (strcmp(name, iface)) {
972            continue;
973        }
974        fclose(fp);
975        return 0;
976    }
977
978    fclose(fp);
979    *rx = 0;
980    *tx = 0;
981    return 0;
982}
983
984CommandListener::BandwidthControlCmd::BandwidthControlCmd() :
985    NetdCommand("bandwidth") {
986}
987
988void CommandListener::BandwidthControlCmd::sendGenericSyntaxError(SocketClient *cli, const char *usageMsg) {
989    char *msg;
990    asprintf(&msg, "Usage: bandwidth %s", usageMsg);
991    cli->sendMsg(ResponseCode::CommandSyntaxError, msg, false);
992    free(msg);
993}
994
995void CommandListener::BandwidthControlCmd::sendGenericOkFail(SocketClient *cli, int cond) {
996    if (!cond) {
997        cli->sendMsg(ResponseCode::CommandOkay, "Bandwidth command succeeeded", false);
998    } else {
999        cli->sendMsg(ResponseCode::OperationFailed, "Bandwidth command failed", false);
1000    }
1001}
1002
1003void CommandListener::BandwidthControlCmd::sendGenericOpFailed(SocketClient *cli, const char *errMsg) {
1004    cli->sendMsg(ResponseCode::OperationFailed, errMsg, false);
1005}
1006
1007int CommandListener::BandwidthControlCmd::runCommand(SocketClient *cli, int argc, char **argv) {
1008    if (argc < 2) {
1009        sendGenericSyntaxError(cli, "<cmds> <args...>");
1010        return 0;
1011    }
1012
1013    ALOGV("bwctrlcmd: argc=%d %s %s ...", argc, argv[0], argv[1]);
1014
1015    if (!strcmp(argv[1], "enable")) {
1016        int rc = sBandwidthCtrl->enableBandwidthControl(true);
1017        sendGenericOkFail(cli, rc);
1018        return 0;
1019
1020    }
1021    if (!strcmp(argv[1], "disable")) {
1022        int rc = sBandwidthCtrl->disableBandwidthControl();
1023        sendGenericOkFail(cli, rc);
1024        return 0;
1025
1026    }
1027    if (!strcmp(argv[1], "removequota") || !strcmp(argv[1], "rq")) {
1028        if (argc != 3) {
1029            sendGenericSyntaxError(cli, "removequota <interface>");
1030            return 0;
1031        }
1032        int rc = sBandwidthCtrl->removeInterfaceSharedQuota(argv[2]);
1033        sendGenericOkFail(cli, rc);
1034        return 0;
1035
1036    }
1037    if (!strcmp(argv[1], "getquota") || !strcmp(argv[1], "gq")) {
1038        int64_t bytes;
1039        if (argc != 2) {
1040            sendGenericSyntaxError(cli, "getquota");
1041            return 0;
1042        }
1043        int rc = sBandwidthCtrl->getInterfaceSharedQuota(&bytes);
1044        if (rc) {
1045            sendGenericOpFailed(cli, "Failed to get quota");
1046            return 0;
1047        }
1048
1049        char *msg;
1050        asprintf(&msg, "%lld", bytes);
1051        cli->sendMsg(ResponseCode::QuotaCounterResult, msg, false);
1052        free(msg);
1053        return 0;
1054
1055    }
1056    if (!strcmp(argv[1], "getiquota") || !strcmp(argv[1], "giq")) {
1057        int64_t bytes;
1058        if (argc != 3) {
1059            sendGenericSyntaxError(cli, "getiquota <iface>");
1060            return 0;
1061        }
1062
1063        int rc = sBandwidthCtrl->getInterfaceQuota(argv[2], &bytes);
1064        if (rc) {
1065            sendGenericOpFailed(cli, "Failed to get quota");
1066            return 0;
1067        }
1068        char *msg;
1069        asprintf(&msg, "%lld", bytes);
1070        cli->sendMsg(ResponseCode::QuotaCounterResult, msg, false);
1071        free(msg);
1072        return 0;
1073
1074    }
1075    if (!strcmp(argv[1], "setquota") || !strcmp(argv[1], "sq")) {
1076        if (argc != 4) {
1077            sendGenericSyntaxError(cli, "setquota <interface> <bytes>");
1078            return 0;
1079        }
1080        int rc = sBandwidthCtrl->setInterfaceSharedQuota(argv[2], atoll(argv[3]));
1081        sendGenericOkFail(cli, rc);
1082        return 0;
1083    }
1084    if (!strcmp(argv[1], "setquotas") || !strcmp(argv[1], "sqs")) {
1085        int rc;
1086        if (argc < 4) {
1087            sendGenericSyntaxError(cli, "setquotas <bytes> <interface> ...");
1088            return 0;
1089        }
1090
1091        for (int q = 3; argc >= 4; q++, argc--) {
1092            rc = sBandwidthCtrl->setInterfaceSharedQuota(argv[q], atoll(argv[2]));
1093            if (rc) {
1094                char *msg;
1095                asprintf(&msg, "bandwidth setquotas %s %s failed", argv[2], argv[q]);
1096                cli->sendMsg(ResponseCode::OperationFailed,
1097                             msg, false);
1098                free(msg);
1099                return 0;
1100            }
1101        }
1102        sendGenericOkFail(cli, rc);
1103        return 0;
1104
1105    }
1106    if (!strcmp(argv[1], "removequotas") || !strcmp(argv[1], "rqs")) {
1107        int rc;
1108        if (argc < 3) {
1109            sendGenericSyntaxError(cli, "removequotas <interface> ...");
1110            return 0;
1111        }
1112
1113        for (int q = 2; argc >= 3; q++, argc--) {
1114            rc = sBandwidthCtrl->removeInterfaceSharedQuota(argv[q]);
1115            if (rc) {
1116                char *msg;
1117                asprintf(&msg, "bandwidth removequotas %s failed", argv[q]);
1118                cli->sendMsg(ResponseCode::OperationFailed,
1119                             msg, false);
1120                free(msg);
1121                return 0;
1122            }
1123        }
1124        sendGenericOkFail(cli, rc);
1125        return 0;
1126
1127    }
1128    if (!strcmp(argv[1], "removeiquota") || !strcmp(argv[1], "riq")) {
1129        if (argc != 3) {
1130            sendGenericSyntaxError(cli, "removeiquota <interface>");
1131            return 0;
1132        }
1133        int rc = sBandwidthCtrl->removeInterfaceQuota(argv[2]);
1134        sendGenericOkFail(cli, rc);
1135        return 0;
1136
1137    }
1138    if (!strcmp(argv[1], "setiquota") || !strcmp(argv[1], "siq")) {
1139        if (argc != 4) {
1140            sendGenericSyntaxError(cli, "setiquota <interface> <bytes>");
1141            return 0;
1142        }
1143        int rc = sBandwidthCtrl->setInterfaceQuota(argv[2], atoll(argv[3]));
1144        sendGenericOkFail(cli, rc);
1145        return 0;
1146
1147    }
1148    if (!strcmp(argv[1], "addnaughtyapps") || !strcmp(argv[1], "ana")) {
1149        if (argc < 3) {
1150            sendGenericSyntaxError(cli, "addnaughtyapps <appUid> ...");
1151            return 0;
1152        }
1153        int rc = sBandwidthCtrl->addNaughtyApps(argc - 2, argv + 2);
1154        sendGenericOkFail(cli, rc);
1155        return 0;
1156
1157
1158    }
1159    if (!strcmp(argv[1], "removenaughtyapps") || !strcmp(argv[1], "rna")) {
1160        if (argc < 3) {
1161            sendGenericSyntaxError(cli, "removenaughtyapps <appUid> ...");
1162            return 0;
1163        }
1164        int rc = sBandwidthCtrl->removeNaughtyApps(argc - 2, argv + 2);
1165        sendGenericOkFail(cli, rc);
1166        return 0;
1167
1168    }
1169    if (!strcmp(argv[1], "setglobalalert") || !strcmp(argv[1], "sga")) {
1170        if (argc != 3) {
1171            sendGenericSyntaxError(cli, "setglobalalert <bytes>");
1172            return 0;
1173        }
1174        int rc = sBandwidthCtrl->setGlobalAlert(atoll(argv[2]));
1175        sendGenericOkFail(cli, rc);
1176        return 0;
1177
1178    }
1179    if (!strcmp(argv[1], "debugsettetherglobalalert") || !strcmp(argv[1], "dstga")) {
1180        if (argc != 4) {
1181            sendGenericSyntaxError(cli, "debugsettetherglobalalert <interface0> <interface1>");
1182            return 0;
1183        }
1184        /* We ignore the interfaces for now. */
1185        int rc = sBandwidthCtrl->setGlobalAlertInForwardChain();
1186        sendGenericOkFail(cli, rc);
1187        return 0;
1188
1189    }
1190    if (!strcmp(argv[1], "removeglobalalert") || !strcmp(argv[1], "rga")) {
1191        if (argc != 2) {
1192            sendGenericSyntaxError(cli, "removeglobalalert");
1193            return 0;
1194        }
1195        int rc = sBandwidthCtrl->removeGlobalAlert();
1196        sendGenericOkFail(cli, rc);
1197        return 0;
1198
1199    }
1200    if (!strcmp(argv[1], "debugremovetetherglobalalert") || !strcmp(argv[1], "drtga")) {
1201        if (argc != 4) {
1202            sendGenericSyntaxError(cli, "debugremovetetherglobalalert <interface0> <interface1>");
1203            return 0;
1204        }
1205        /* We ignore the interfaces for now. */
1206        int rc = sBandwidthCtrl->removeGlobalAlertInForwardChain();
1207        sendGenericOkFail(cli, rc);
1208        return 0;
1209
1210    }
1211    if (!strcmp(argv[1], "setsharedalert") || !strcmp(argv[1], "ssa")) {
1212        if (argc != 3) {
1213            sendGenericSyntaxError(cli, "setsharedalert <bytes>");
1214            return 0;
1215        }
1216        int rc = sBandwidthCtrl->setSharedAlert(atoll(argv[2]));
1217        sendGenericOkFail(cli, rc);
1218        return 0;
1219
1220    }
1221    if (!strcmp(argv[1], "removesharedalert") || !strcmp(argv[1], "rsa")) {
1222        if (argc != 2) {
1223            sendGenericSyntaxError(cli, "removesharedalert");
1224            return 0;
1225        }
1226        int rc = sBandwidthCtrl->removeSharedAlert();
1227        sendGenericOkFail(cli, rc);
1228        return 0;
1229
1230    }
1231    if (!strcmp(argv[1], "setinterfacealert") || !strcmp(argv[1], "sia")) {
1232        if (argc != 4) {
1233            sendGenericSyntaxError(cli, "setinterfacealert <interface> <bytes>");
1234            return 0;
1235        }
1236        int rc = sBandwidthCtrl->setInterfaceAlert(argv[2], atoll(argv[3]));
1237        sendGenericOkFail(cli, rc);
1238        return 0;
1239
1240    }
1241    if (!strcmp(argv[1], "removeinterfacealert") || !strcmp(argv[1], "ria")) {
1242        if (argc != 3) {
1243            sendGenericSyntaxError(cli, "removeinterfacealert <interface>");
1244            return 0;
1245        }
1246        int rc = sBandwidthCtrl->removeInterfaceAlert(argv[2]);
1247        sendGenericOkFail(cli, rc);
1248        return 0;
1249
1250    }
1251    if (!strcmp(argv[1], "gettetherstats") || !strcmp(argv[1], "gts")) {
1252        BandwidthController::TetherStats tetherStats;
1253        std::string extraProcessingInfo = "";
1254        if (argc != 4) {
1255            sendGenericSyntaxError(cli, "gettetherstats <interface0> <interface1>");
1256            return 0;
1257        }
1258
1259        tetherStats.ifaceIn = argv[2];
1260        tetherStats.ifaceOut = argv[3];
1261        int rc = sBandwidthCtrl->getTetherStats(tetherStats, extraProcessingInfo);
1262        if (rc) {
1263                extraProcessingInfo.insert(0, "Failed to get tethering stats.\n");
1264                sendGenericOpFailed(cli, extraProcessingInfo.c_str());
1265            return 0;
1266        }
1267
1268        char *msg = tetherStats.getStatsLine();
1269        cli->sendMsg(ResponseCode::TetheringStatsResult, msg, false);
1270        free(msg);
1271        return 0;
1272
1273    }
1274
1275    cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown bandwidth cmd", false);
1276    return 0;
1277}
1278
1279CommandListener::IdletimerControlCmd::IdletimerControlCmd() :
1280    NetdCommand("idletimer") {
1281}
1282
1283int CommandListener::IdletimerControlCmd::runCommand(SocketClient *cli, int argc, char **argv) {
1284  // TODO(ashish): Change the error statements
1285    if (argc < 2) {
1286        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
1287        return 0;
1288    }
1289
1290    ALOGV("idletimerctrlcmd: argc=%d %s %s ...", argc, argv[0], argv[1]);
1291
1292    if (!strcmp(argv[1], "enable")) {
1293      if (0 != sIdletimerCtrl->enableIdletimerControl()) {
1294        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
1295      } else {
1296        cli->sendMsg(ResponseCode::CommandOkay, "Enable success", false);
1297      }
1298      return 0;
1299
1300    }
1301    if (!strcmp(argv[1], "disable")) {
1302      if (0 != sIdletimerCtrl->disableIdletimerControl()) {
1303        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
1304      } else {
1305        cli->sendMsg(ResponseCode::CommandOkay, "Disable success", false);
1306      }
1307      return 0;
1308    }
1309    if (!strcmp(argv[1], "add")) {
1310        if (argc != 5) {
1311            cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
1312            return 0;
1313        }
1314        if(0 != sIdletimerCtrl->addInterfaceIdletimer(
1315                                        argv[2], atoi(argv[3]), argv[4])) {
1316          cli->sendMsg(ResponseCode::OperationFailed, "Failed to add interface", false);
1317        } else {
1318          cli->sendMsg(ResponseCode::CommandOkay,  "Add success", false);
1319        }
1320        return 0;
1321    }
1322    if (!strcmp(argv[1], "remove")) {
1323        if (argc != 5) {
1324            cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
1325            return 0;
1326        }
1327        // ashish: fixme timeout
1328        if (0 != sIdletimerCtrl->removeInterfaceIdletimer(
1329                                        argv[2], atoi(argv[3]), argv[4])) {
1330          cli->sendMsg(ResponseCode::OperationFailed, "Failed to remove interface", false);
1331        } else {
1332          cli->sendMsg(ResponseCode::CommandOkay, "Remove success", false);
1333        }
1334        return 0;
1335    }
1336
1337    cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown idletimer cmd", false);
1338    return 0;
1339}
1340