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