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#include <stdlib.h>
18#include <sys/socket.h>
19#include <sys/types.h>
20#include <netinet/in.h>
21#include <arpa/inet.h>
22#include <dirent.h>
23#include <errno.h>
24
25#include <linux/if.h>
26
27#define LOG_TAG "CommandListener"
28#include <cutils/log.h>
29
30#include <sysutils/SocketClient.h>
31
32#include "CommandListener.h"
33#include "ResponseCode.h"
34#include "ThrottleController.h"
35
36
37extern "C" int ifc_init(void);
38extern "C" int ifc_get_hwaddr(const char *name, void *ptr);
39extern "C" int ifc_get_info(const char *name, in_addr_t *addr, in_addr_t *mask, unsigned *flags);
40extern "C" int ifc_set_addr(const char *name, in_addr_t addr);
41extern "C" int ifc_set_mask(const char *name, in_addr_t mask);
42extern "C" int ifc_up(const char *name);
43extern "C" int ifc_down(const char *name);
44
45TetherController *CommandListener::sTetherCtrl = NULL;
46NatController *CommandListener::sNatCtrl = NULL;
47PppController *CommandListener::sPppCtrl = NULL;
48PanController *CommandListener::sPanCtrl = NULL;
49SoftapController *CommandListener::sSoftapCtrl = NULL;
50UsbController *CommandListener::sUsbCtrl = NULL;
51
52CommandListener::CommandListener() :
53                 FrameworkListener("netd") {
54    registerCmd(new InterfaceCmd());
55    registerCmd(new IpFwdCmd());
56    registerCmd(new TetherCmd());
57    registerCmd(new NatCmd());
58    registerCmd(new ListTtysCmd());
59    registerCmd(new PppdCmd());
60    registerCmd(new PanCmd());
61    registerCmd(new SoftapCmd());
62    registerCmd(new UsbCmd());
63
64    if (!sTetherCtrl)
65        sTetherCtrl = new TetherController();
66    if (!sNatCtrl)
67        sNatCtrl = new NatController();
68    if (!sPppCtrl)
69        sPppCtrl = new PppController();
70    if (!sPanCtrl)
71        sPanCtrl = new PanController();
72    if (!sSoftapCtrl)
73        sSoftapCtrl = new SoftapController();
74    if (!sUsbCtrl)
75        sUsbCtrl = new UsbController();
76}
77
78CommandListener::InterfaceCmd::InterfaceCmd() :
79                 NetdCommand("interface") {
80}
81
82int CommandListener::InterfaceCmd::runCommand(SocketClient *cli,
83                                                      int argc, char **argv) {
84    if (argc < 2) {
85        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
86        return 0;
87    }
88
89    if (!strcmp(argv[1], "list")) {
90        DIR *d;
91        struct dirent *de;
92
93        if (!(d = opendir("/sys/class/net"))) {
94            cli->sendMsg(ResponseCode::OperationFailed, "Failed to open sysfs dir", true);
95            return 0;
96        }
97
98        while((de = readdir(d))) {
99            if (de->d_name[0] == '.')
100                continue;
101            cli->sendMsg(ResponseCode::InterfaceListResult, de->d_name, false);
102        }
103        closedir(d);
104        cli->sendMsg(ResponseCode::CommandOkay, "Interface list completed", false);
105        return 0;
106    } else if (!strcmp(argv[1], "readrxcounter")) {
107        if (argc != 3) {
108            cli->sendMsg(ResponseCode::CommandSyntaxError,
109                    "Usage: interface readrxcounter <interface>", false);
110            return 0;
111        }
112        unsigned long rx = 0, tx = 0;
113        if (readInterfaceCounters(argv[2], &rx, &tx)) {
114            cli->sendMsg(ResponseCode::OperationFailed, "Failed to read counters", true);
115            return 0;
116        }
117
118        char *msg;
119        asprintf(&msg, "%lu", rx);
120        cli->sendMsg(ResponseCode::InterfaceRxCounterResult, msg, false);
121        free(msg);
122
123        return 0;
124    } else if (!strcmp(argv[1], "readtxcounter")) {
125        if (argc != 3) {
126            cli->sendMsg(ResponseCode::CommandSyntaxError,
127                    "Usage: interface readtxcounter <interface>", false);
128            return 0;
129        }
130        unsigned long rx = 0, tx = 0;
131        if (readInterfaceCounters(argv[2], &rx, &tx)) {
132            cli->sendMsg(ResponseCode::OperationFailed, "Failed to read counters", true);
133            return 0;
134        }
135
136        char *msg = NULL;
137        asprintf(&msg, "%lu", tx);
138        cli->sendMsg(ResponseCode::InterfaceTxCounterResult, msg, false);
139        free(msg);
140        return 0;
141    } else if (!strcmp(argv[1], "getthrottle")) {
142        if (argc != 4 || (argc == 4 && (strcmp(argv[3], "rx") && (strcmp(argv[3], "tx"))))) {
143            cli->sendMsg(ResponseCode::CommandSyntaxError,
144                    "Usage: interface getthrottle <interface> <rx|tx>", false);
145            return 0;
146        }
147        int val = 0;
148        int rc = 0;
149        int voldRc = ResponseCode::InterfaceRxThrottleResult;
150
151        if (!strcmp(argv[3], "rx")) {
152            rc = ThrottleController::getInterfaceRxThrottle(argv[2], &val);
153        } else {
154            rc = ThrottleController::getInterfaceTxThrottle(argv[2], &val);
155            voldRc = ResponseCode::InterfaceTxThrottleResult;
156        }
157        if (rc) {
158            cli->sendMsg(ResponseCode::OperationFailed, "Failed to get throttle", true);
159        } else {
160            char *msg = NULL;
161            asprintf(&msg, "%u", val);
162            cli->sendMsg(voldRc, msg, false);
163            free(msg);
164            return 0;
165        }
166        return 0;
167    } else if (!strcmp(argv[1], "setthrottle")) {
168        if (argc != 5) {
169            cli->sendMsg(ResponseCode::CommandSyntaxError,
170                    "Usage: interface setthrottle <interface> <rx_kbps> <tx_kbps>", false);
171            return 0;
172        }
173        if (ThrottleController::setInterfaceThrottle(argv[2], atoi(argv[3]), atoi(argv[4]))) {
174            cli->sendMsg(ResponseCode::OperationFailed, "Failed to set throttle", true);
175        } else {
176            cli->sendMsg(ResponseCode::CommandOkay, "Interface throttling set", false);
177        }
178        return 0;
179    } else {
180        /*
181         * These commands take a minimum of 3 arguments
182         */
183        if (argc < 3) {
184            cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
185            return 0;
186        }
187        if (!strcmp(argv[1], "getcfg")) {
188            struct in_addr addr, mask;
189            unsigned char hwaddr[6];
190            unsigned flags = 0;
191
192            ifc_init();
193            memset(hwaddr, 0, sizeof(hwaddr));
194
195            if (ifc_get_info(argv[2], &addr.s_addr, &mask.s_addr, &flags)) {
196                cli->sendMsg(ResponseCode::OperationFailed, "Interface not found", true);
197                return 0;
198            }
199
200            if (ifc_get_hwaddr(argv[2], (void *) hwaddr)) {
201                LOGW("Failed to retrieve HW addr for %s (%s)", argv[2], strerror(errno));
202            }
203
204            char *addr_s = strdup(inet_ntoa(addr));
205            char *mask_s = strdup(inet_ntoa(mask));
206            const char *updown, *brdcst, *loopbk, *ppp, *running, *multi;
207
208            updown =  (flags & IFF_UP)           ? "up" : "down";
209            brdcst =  (flags & IFF_BROADCAST)    ? " broadcast" : "";
210            loopbk =  (flags & IFF_LOOPBACK)     ? " loopback" : "";
211            ppp =     (flags & IFF_POINTOPOINT)  ? " point-to-point" : "";
212            running = (flags & IFF_RUNNING)      ? " running" : "";
213            multi =   (flags & IFF_MULTICAST)    ? " multicast" : "";
214
215            char *flag_s;
216
217            asprintf(&flag_s, "[%s%s%s%s%s%s]", updown, brdcst, loopbk, ppp, running, multi);
218
219            char *msg = NULL;
220            asprintf(&msg, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x %s %s %s",
221                     hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5],
222                     addr_s, mask_s, flag_s);
223
224            cli->sendMsg(ResponseCode::InterfaceGetCfgResult, msg, false);
225
226            free(addr_s);
227            free(mask_s);
228            free(flag_s);
229            free(msg);
230            return 0;
231        } else if (!strcmp(argv[1], "setcfg")) {
232            // arglist: iface addr mask [flags]
233            if (argc < 5) {
234                cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
235                return 0;
236            }
237            LOGD("Setting iface cfg");
238
239            struct in_addr addr, mask;
240            unsigned flags = 0;
241
242            if (!inet_aton(argv[3], &addr)) {
243                cli->sendMsg(ResponseCode::CommandParameterError, "Invalid address", false);
244                return 0;
245            }
246
247            if (!inet_aton(argv[4], &mask)) {
248                cli->sendMsg(ResponseCode::CommandParameterError, "Invalid netmask", false);
249                return 0;
250            }
251
252            ifc_init();
253            if (ifc_set_addr(argv[2], addr.s_addr)) {
254                cli->sendMsg(ResponseCode::OperationFailed, "Failed to set address", true);
255                return 0;
256            }
257
258            if (ifc_set_mask(argv[2], mask.s_addr)) {
259                cli->sendMsg(ResponseCode::OperationFailed, "Failed to set netmask", true);
260                return 0;
261            }
262
263            /* Process flags */
264            /* read from "[XX" arg to "YY]" arg */
265            bool bStarted = false;
266            for (int i = 5; i < argc; i++) {
267                char *flag = argv[i];
268                if (!bStarted) {
269                    if (*flag == '[') {
270                        flag++;
271                        bStarted = true;
272                    } else {
273                        continue;
274                    }
275                }
276                int len = strlen(flag);
277                if (flag[len-1] == ']') {
278                    i = argc;  // stop after this loop
279                    flag[len-1] = 0;
280                }
281                if (!strcmp(flag, "up")) {
282                    LOGD("Trying to bring up %s", argv[2]);
283                    if (ifc_up(argv[2])) {
284                        LOGE("Error upping interface");
285                        cli->sendMsg(ResponseCode::OperationFailed, "Failed to up interface", true);
286                        return 0;
287                    }
288                } else if (!strcmp(flag, "down")) {
289                    LOGD("Trying to bring down %s", argv[2]);
290                    if (ifc_down(argv[2])) {
291                        LOGE("Error downing interface");
292                        cli->sendMsg(ResponseCode::OperationFailed, "Failed to down interface", true);
293                        return 0;
294                    }
295                } else if (!strcmp(flag, "broadcast")) {
296                    LOGD("broadcast flag ignored");
297                } else if (!strcmp(flag, "multicast")) {
298                    LOGD("multicast flag ignored");
299                } else {
300                    cli->sendMsg(ResponseCode::CommandParameterError, "Flag unsupported", false);
301                    return 0;
302                }
303            }
304            cli->sendMsg(ResponseCode::CommandOkay, "Interface configuration set", false);
305            return 0;
306        } else {
307            cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown interface cmd", false);
308            return 0;
309        }
310    }
311    return 0;
312}
313
314CommandListener::ListTtysCmd::ListTtysCmd() :
315                 NetdCommand("list_ttys") {
316}
317
318int CommandListener::ListTtysCmd::runCommand(SocketClient *cli,
319                                             int argc, char **argv) {
320    TtyCollection *tlist = sPppCtrl->getTtyList();
321    TtyCollection::iterator it;
322
323    for (it = tlist->begin(); it != tlist->end(); ++it) {
324        cli->sendMsg(ResponseCode::TtyListResult, *it, false);
325    }
326
327    cli->sendMsg(ResponseCode::CommandOkay, "Ttys listed.", false);
328    return 0;
329}
330
331CommandListener::IpFwdCmd::IpFwdCmd() :
332                 NetdCommand("ipfwd") {
333}
334
335int CommandListener::IpFwdCmd::runCommand(SocketClient *cli,
336                                                      int argc, char **argv) {
337    int rc = 0;
338
339    if (argc < 2) {
340        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
341        return 0;
342    }
343
344    if (!strcmp(argv[1], "status")) {
345        char *tmp = NULL;
346
347        asprintf(&tmp, "Forwarding %s", (sTetherCtrl->getIpFwdEnabled() ? "enabled" : "disabled"));
348        cli->sendMsg(ResponseCode::IpFwdStatusResult, tmp, false);
349        free(tmp);
350        return 0;
351    } else if (!strcmp(argv[1], "enable")) {
352        rc = sTetherCtrl->setIpFwdEnabled(true);
353    } else if (!strcmp(argv[1], "disable")) {
354        rc = sTetherCtrl->setIpFwdEnabled(false);
355    } else {
356        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown ipfwd cmd", false);
357        return 0;
358    }
359
360    if (!rc) {
361        cli->sendMsg(ResponseCode::CommandOkay, "ipfwd operation succeeded", false);
362    } else {
363        cli->sendMsg(ResponseCode::OperationFailed, "ipfwd operation failed", true);
364    }
365
366    return 0;
367}
368
369CommandListener::TetherCmd::TetherCmd() :
370                 NetdCommand("tether") {
371}
372
373int CommandListener::TetherCmd::runCommand(SocketClient *cli,
374                                                      int argc, char **argv) {
375    int rc = 0;
376
377    if (argc < 2) {
378        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
379        return 0;
380    }
381
382    if (!strcmp(argv[1], "stop")) {
383        rc = sTetherCtrl->stopTethering();
384    } else if (!strcmp(argv[1], "status")) {
385        char *tmp = NULL;
386
387        asprintf(&tmp, "Tethering services %s",
388                 (sTetherCtrl->isTetheringStarted() ? "started" : "stopped"));
389        cli->sendMsg(ResponseCode::TetherStatusResult, tmp, false);
390        free(tmp);
391        return 0;
392    } else {
393        /*
394         * These commands take a minimum of 4 arguments
395         */
396        if (argc < 4) {
397            cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
398            return 0;
399        }
400
401        if (!strcmp(argv[1], "start")) {
402            if (argc % 2 == 1) {
403                cli->sendMsg(ResponseCode::CommandSyntaxError, "Bad number of arguments", false);
404                return 0;
405            }
406
407            int num_addrs = argc - 2;
408            int arg_index = 2;
409            int array_index = 0;
410            in_addr *addrs = (in_addr *)malloc(sizeof(in_addr) * num_addrs);
411            while (array_index < num_addrs) {
412                if (!inet_aton(argv[arg_index++], &(addrs[array_index++]))) {
413                    cli->sendMsg(ResponseCode::CommandParameterError, "Invalid address", false);
414                    free(addrs);
415                    return 0;
416                }
417            }
418            rc = sTetherCtrl->startTethering(num_addrs, addrs);
419            free(addrs);
420        } else if (!strcmp(argv[1], "interface")) {
421            if (!strcmp(argv[2], "add")) {
422                rc = sTetherCtrl->tetherInterface(argv[3]);
423            } else if (!strcmp(argv[2], "remove")) {
424                rc = sTetherCtrl->untetherInterface(argv[3]);
425            } else if (!strcmp(argv[2], "list")) {
426                InterfaceCollection *ilist = sTetherCtrl->getTetheredInterfaceList();
427                InterfaceCollection::iterator it;
428
429                for (it = ilist->begin(); it != ilist->end(); ++it) {
430                    cli->sendMsg(ResponseCode::TetherInterfaceListResult, *it, false);
431                }
432            } else {
433                cli->sendMsg(ResponseCode::CommandParameterError,
434                             "Unknown tether interface operation", false);
435                return 0;
436            }
437        } else if (!strcmp(argv[1], "dns")) {
438            if (!strcmp(argv[2], "set")) {
439                rc = sTetherCtrl->setDnsForwarders(&argv[3], argc - 3);
440            } else if (!strcmp(argv[2], "list")) {
441                NetAddressCollection *dlist = sTetherCtrl->getDnsForwarders();
442                NetAddressCollection::iterator it;
443
444                for (it = dlist->begin(); it != dlist->end(); ++it) {
445                    cli->sendMsg(ResponseCode::TetherDnsFwdTgtListResult, inet_ntoa(*it), false);
446                }
447            } else {
448                cli->sendMsg(ResponseCode::CommandParameterError,
449                             "Unknown tether interface operation", false);
450                return 0;
451            }
452        } else {
453            cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown tether cmd", false);
454            return 0;
455        }
456    }
457
458    if (!rc) {
459        cli->sendMsg(ResponseCode::CommandOkay, "Tether operation succeeded", false);
460    } else {
461        cli->sendMsg(ResponseCode::OperationFailed, "Tether operation failed", true);
462    }
463
464    return 0;
465}
466
467CommandListener::NatCmd::NatCmd() :
468                 NetdCommand("nat") {
469}
470
471int CommandListener::NatCmd::runCommand(SocketClient *cli,
472                                                      int argc, char **argv) {
473    int rc = 0;
474
475    if (argc < 3) {
476        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
477        return 0;
478    }
479
480    if (!strcmp(argv[1], "enable")) {
481        rc = sNatCtrl->enableNat(argv[2], argv[3]);
482    } else if (!strcmp(argv[1], "disable")) {
483        rc = sNatCtrl->disableNat(argv[2], argv[3]);
484    } else {
485        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown nat cmd", false);
486        return 0;
487    }
488
489    if (!rc) {
490        cli->sendMsg(ResponseCode::CommandOkay, "Nat operation succeeded", false);
491    } else {
492        cli->sendMsg(ResponseCode::OperationFailed, "Nat operation failed", true);
493    }
494
495    return 0;
496}
497
498CommandListener::PppdCmd::PppdCmd() :
499                 NetdCommand("pppd") {
500}
501
502int CommandListener::PppdCmd::runCommand(SocketClient *cli,
503                                                      int argc, char **argv) {
504    int rc = 0;
505
506    if (argc < 3) {
507        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
508        return 0;
509    }
510
511    if (!strcmp(argv[1], "attach")) {
512        struct in_addr l, r, dns1, dns2;
513
514        memset(&dns1, sizeof(struct in_addr), 0);
515        memset(&dns2, sizeof(struct in_addr), 0);
516
517        if (!inet_aton(argv[3], &l)) {
518            cli->sendMsg(ResponseCode::CommandParameterError, "Invalid local address", false);
519            return 0;
520        }
521        if (!inet_aton(argv[4], &r)) {
522            cli->sendMsg(ResponseCode::CommandParameterError, "Invalid remote address", false);
523            return 0;
524        }
525        if ((argc > 3) && (!inet_aton(argv[5], &dns1))) {
526            cli->sendMsg(ResponseCode::CommandParameterError, "Invalid dns1 address", false);
527            return 0;
528        }
529        if ((argc > 4) && (!inet_aton(argv[6], &dns2))) {
530            cli->sendMsg(ResponseCode::CommandParameterError, "Invalid dns2 address", false);
531            return 0;
532        }
533        rc = sPppCtrl->attachPppd(argv[2], l, r, dns1, dns2);
534    } else if (!strcmp(argv[1], "detach")) {
535        rc = sPppCtrl->detachPppd(argv[2]);
536    } else {
537        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown pppd cmd", false);
538        return 0;
539    }
540
541    if (!rc) {
542        cli->sendMsg(ResponseCode::CommandOkay, "Pppd operation succeeded", false);
543    } else {
544        cli->sendMsg(ResponseCode::OperationFailed, "Pppd operation failed", true);
545    }
546
547    return 0;
548}
549
550CommandListener::PanCmd::PanCmd() :
551                 NetdCommand("pan") {
552}
553
554int CommandListener::PanCmd::runCommand(SocketClient *cli,
555                                        int argc, char **argv) {
556    int rc = 0;
557
558    if (argc < 2) {
559        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
560        return 0;
561    }
562
563    if (!strcmp(argv[1], "start")) {
564        rc = sPanCtrl->startPan();
565    } else if (!strcmp(argv[1], "stop")) {
566        rc = sPanCtrl->stopPan();
567    } else if (!strcmp(argv[1], "status")) {
568        char *tmp = NULL;
569
570        asprintf(&tmp, "Pan services %s",
571                 (sPanCtrl->isPanStarted() ? "started" : "stopped"));
572        cli->sendMsg(ResponseCode::PanStatusResult, tmp, false);
573        free(tmp);
574        return 0;
575    } else {
576        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown pan cmd", false);
577        return 0;
578    }
579
580    if (!rc) {
581        cli->sendMsg(ResponseCode::CommandOkay, "Pan operation succeeded", false);
582    } else {
583        cli->sendMsg(ResponseCode::OperationFailed, "Pan operation failed", true);
584    }
585
586    return 0;
587}
588
589CommandListener::SoftapCmd::SoftapCmd() :
590                 NetdCommand("softap") {
591}
592
593int CommandListener::SoftapCmd::runCommand(SocketClient *cli,
594                                        int argc, char **argv) {
595    int rc = 0, flag = 0;
596
597    if (argc < 2) {
598        cli->sendMsg(ResponseCode::CommandSyntaxError, "Softap Missing argument", false);
599        return 0;
600    }
601
602    if (!strcmp(argv[1], "start")) {
603        rc = sSoftapCtrl->startDriver(argv[2]);
604    } else if (!strcmp(argv[1], "stop")) {
605        rc = sSoftapCtrl->stopDriver(argv[2]);
606    } else if (!strcmp(argv[1], "startap")) {
607        rc = sSoftapCtrl->startSoftap();
608    } else if (!strcmp(argv[1], "stopap")) {
609        rc = sSoftapCtrl->stopSoftap();
610    } else if (!strcmp(argv[1], "fwreload")) {
611        rc = sSoftapCtrl->fwReloadSoftap(argc, argv);
612    } else if (!strcmp(argv[1], "status")) {
613        char *tmp = NULL;
614
615        asprintf(&tmp, "Softap service %s",
616                 (sSoftapCtrl->isSoftapStarted() ? "started" : "stopped"));
617        cli->sendMsg(ResponseCode::SoftapStatusResult, tmp, false);
618        free(tmp);
619        return 0;
620    } else if (!strcmp(argv[1], "set")) {
621        rc = sSoftapCtrl->setSoftap(argc, argv);
622    } else {
623        cli->sendMsg(ResponseCode::CommandSyntaxError, "Softap Unknown cmd", false);
624        return 0;
625    }
626
627    if (!rc) {
628        cli->sendMsg(ResponseCode::CommandOkay, "Softap operation succeeded", false);
629    } else {
630        cli->sendMsg(ResponseCode::OperationFailed, "Softap operation failed", true);
631    }
632
633    return 0;
634}
635
636CommandListener::UsbCmd::UsbCmd() :
637                 NetdCommand("usb") {
638}
639
640int CommandListener::UsbCmd::runCommand(SocketClient *cli, int argc, char **argv) {
641    int rc = 0;
642
643    if (argc < 2) {
644        cli->sendMsg(ResponseCode::CommandSyntaxError, "Usb Missing argument", false);
645        return 0;
646    }
647
648    if (!strcmp(argv[1], "startrndis")) {
649        rc = sUsbCtrl->startRNDIS();
650    } else if (!strcmp(argv[1], "stoprndis")) {
651        rc = sUsbCtrl->stopRNDIS();
652    } else if (!strcmp(argv[1], "rndisstatus")) {
653        char *tmp = NULL;
654
655        asprintf(&tmp, "Usb RNDIS %s",
656                (sUsbCtrl->isRNDISStarted() ? "started" : "stopped"));
657        cli->sendMsg(ResponseCode::UsbRNDISStatusResult, tmp, false);
658        free(tmp);
659        return 0;
660    } else {
661        cli->sendMsg(ResponseCode::CommandSyntaxError, "Usb Unknown cmd", false);
662        return 0;
663    }
664
665    if (!rc) {
666        cli->sendMsg(ResponseCode::CommandOkay, "Usb operation succeeded", false);
667    } else {
668        cli->sendMsg(ResponseCode::OperationFailed, "Softap operation failed", true);
669    }
670
671    return 0;
672}
673
674int CommandListener::readInterfaceCounters(const char *iface, unsigned long *rx, unsigned long *tx) {
675    FILE *fp = fopen("/proc/net/dev", "r");
676    if (!fp) {
677        LOGE("Failed to open /proc/net/dev (%s)", strerror(errno));
678        return -1;
679    }
680
681    char buffer[512];
682
683    fgets(buffer, sizeof(buffer), fp); // Header 1
684    fgets(buffer, sizeof(buffer), fp); // Header 2
685    while(fgets(buffer, sizeof(buffer), fp)) {
686        buffer[strlen(buffer)-1] = '\0';
687
688        char name[31];
689        unsigned long d;
690        sscanf(buffer, "%30s %lu %lu %lu %lu %lu %lu %lu %lu %lu",
691                name, rx, &d, &d, &d, &d, &d, &d, &d, tx);
692        char *rxString = strchr(name, ':');
693        *rxString = '\0';
694        rxString++;
695        // when the rx count gets too big it changes from "name: 999" to "name:1000"
696        // and the sscanf munge the two together.  Detect that and fix
697        // note that all the %lu will be off by one and the real tx value will be in d
698        if (*rxString != '\0') {
699            *tx = d;
700            sscanf(rxString, "%20lu", rx);
701        }
702        if (strcmp(name, iface)) {
703            continue;
704        }
705        fclose(fp);
706        return 0;
707    }
708
709    fclose(fp);
710    *rx = 0;
711    *tx = 0;
712    return 0;
713}
714