OSDN Git Service

Merge "softap: Add delay after driver start, return 0 if softap was started" into...
[android-x86/system-netd.git] / CommandListener.cpp
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
37 extern "C" int ifc_init(void);
38 extern "C" int ifc_get_hwaddr(const char *name, void *ptr);
39 extern "C" int ifc_get_info(const char *name, in_addr_t *addr, in_addr_t *mask, unsigned *flags);
40 extern "C" int ifc_set_addr(const char *name, in_addr_t addr);
41 extern "C" int ifc_set_mask(const char *name, in_addr_t mask);
42 extern "C" int ifc_up(const char *name);
43 extern "C" int ifc_down(const char *name);
44
45 TetherController *CommandListener::sTetherCtrl = NULL;
46 NatController *CommandListener::sNatCtrl = NULL;
47 PppController *CommandListener::sPppCtrl = NULL;
48 PanController *CommandListener::sPanCtrl = NULL;
49 SoftapController *CommandListener::sSoftapCtrl = NULL;
50 UsbController *CommandListener::sUsbCtrl = NULL;
51
52 CommandListener::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
78 CommandListener::InterfaceCmd::InterfaceCmd() :
79                  NetdCommand("interface") {
80 }
81
82 int 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
314 CommandListener::ListTtysCmd::ListTtysCmd() :
315                  NetdCommand("list_ttys") {
316 }
317
318 int 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
331 CommandListener::IpFwdCmd::IpFwdCmd() :
332                  NetdCommand("ipfwd") {
333 }
334
335 int 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
369 CommandListener::TetherCmd::TetherCmd() :
370                  NetdCommand("tether") {
371 }
372
373 int 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
467 CommandListener::NatCmd::NatCmd() :
468                  NetdCommand("nat") {
469 }
470
471 int 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
498 CommandListener::PppdCmd::PppdCmd() :
499                  NetdCommand("pppd") {
500 }
501
502 int 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
550 CommandListener::PanCmd::PanCmd() :
551                  NetdCommand("pan") {
552 }
553
554 int 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
589 CommandListener::SoftapCmd::SoftapCmd() :
590                  NetdCommand("softap") {
591 }
592
593 int 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
636 CommandListener::UsbCmd::UsbCmd() :
637                  NetdCommand("usb") {
638 }
639
640 int 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
674 int 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 }