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