CommandListener.cpp revision 3208ea0b6cce28e7aef8459d548fd86df329e34f
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 {
105        /*
106         * These commands take a minimum of 3 arguments
107         */
108        if (argc < 3) {
109            cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
110            return 0;
111        }
112        if (!strcmp(argv[1], "getcfg")) {
113            struct in_addr addr, mask;
114            unsigned char hwaddr[6];
115            unsigned flags = 0;
116
117            ifc_init();
118            memset(hwaddr, 0, sizeof(hwaddr));
119
120            if (ifc_get_info(argv[2], &addr.s_addr, &mask.s_addr, &flags)) {
121                cli->sendMsg(ResponseCode::OperationFailed, "Interface not found", true);
122                return 0;
123            }
124
125            if (ifc_get_hwaddr(argv[2], (void *) hwaddr)) {
126                LOGW("Failed to retrieve HW addr for %s (%s)", argv[2], strerror(errno));
127            }
128
129            char *addr_s = strdup(inet_ntoa(addr));
130            char *mask_s = strdup(inet_ntoa(mask));
131            const char *updown, *brdcst, *loopbk, *ppp, *running, *multi;
132
133            updown =  (flags & IFF_UP)           ? "up" : "down";
134            brdcst =  (flags & IFF_BROADCAST)    ? " broadcast" : "";
135            loopbk =  (flags & IFF_LOOPBACK)     ? " loopback" : "";
136            ppp =     (flags & IFF_POINTOPOINT)  ? " point-to-point" : "";
137            running = (flags & IFF_RUNNING)      ? " running" : "";
138            multi =   (flags & IFF_MULTICAST)    ? " multicast" : "";
139
140            char *flag_s;
141
142            asprintf(&flag_s, "[%s%s%s%s%s%s]", updown, brdcst, loopbk, ppp, running, multi);
143
144            char *msg = NULL;
145            asprintf(&msg, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x %s %s %s",
146                     hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5],
147                     addr_s, mask_s, flag_s);
148
149            cli->sendMsg(ResponseCode::InterfaceGetCfgResult, msg, false);
150
151            free(addr_s);
152            free(mask_s);
153            free(flag_s);
154            free(msg);
155            return 0;
156        } else if (!strcmp(argv[1], "setcfg")) {
157            // arglist: iface addr mask [flags]
158            if (argc < 5) {
159                cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
160                return 0;
161            }
162            LOGD("Setting iface cfg");
163
164            struct in_addr addr, mask;
165            unsigned flags = 0;
166
167            if (!inet_aton(argv[3], &addr)) {
168                cli->sendMsg(ResponseCode::CommandParameterError, "Invalid address", false);
169                return 0;
170            }
171
172            if (!inet_aton(argv[4], &mask)) {
173                cli->sendMsg(ResponseCode::CommandParameterError, "Invalid netmask", false);
174                return 0;
175            }
176
177            ifc_init();
178            if (ifc_set_addr(argv[2], addr.s_addr)) {
179                cli->sendMsg(ResponseCode::OperationFailed, "Failed to set address", true);
180                return 0;
181            }
182
183            if (ifc_set_mask(argv[2], mask.s_addr)) {
184                cli->sendMsg(ResponseCode::OperationFailed, "Failed to set netmask", true);
185                return 0;
186            }
187
188            /* Process flags */
189            /* read from "[XX" arg to "YY]" arg */
190            bool bStarted = false;
191            for (int i = 5; i < argc; i++) {
192                char *flag = argv[i];
193                if (!bStarted) {
194                    if (*flag == '[') {
195                        flag++;
196                        bStarted = true;
197                    } else {
198                        continue;
199                    }
200                }
201                int len = strlen(flag);
202                if (flag[len-1] == ']') {
203                    i = argc;  // stop after this loop
204                    flag[len-1] = 0;
205                }
206                if (!strcmp(flag, "up")) {
207                    LOGD("Trying to bring up %s", argv[2]);
208                    if (ifc_up(argv[2])) {
209                        LOGE("Error upping interface");
210                        cli->sendMsg(ResponseCode::OperationFailed, "Failed to up interface", true);
211                        return 0;
212                    }
213                } else if (!strcmp(flag, "down")) {
214                    LOGD("Trying to bring down %s", argv[2]);
215                    if (ifc_down(argv[2])) {
216                        LOGE("Error downing interface");
217                        cli->sendMsg(ResponseCode::OperationFailed, "Failed to down interface", true);
218                        return 0;
219                    }
220                } else if (!strcmp(flag, "broadcast")) {
221                    LOGD("broadcast flag ignored");
222                } else if (!strcmp(flag, "multicast")) {
223                    LOGD("multicast flag ignored");
224                } else {
225                    cli->sendMsg(ResponseCode::CommandParameterError, "Flag unsupported", false);
226                    return 0;
227                }
228            }
229            cli->sendMsg(ResponseCode::CommandOkay, "Interface configuration set", false);
230            return 0;
231        } else {
232            cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown interface cmd", false);
233            return 0;
234        }
235    }
236    return 0;
237}
238
239CommandListener::ListTtysCmd::ListTtysCmd() :
240                 NetdCommand("list_ttys") {
241}
242
243int CommandListener::ListTtysCmd::runCommand(SocketClient *cli,
244                                             int argc, char **argv) {
245    TtyCollection *tlist = sPppCtrl->getTtyList();
246    TtyCollection::iterator it;
247
248    for (it = tlist->begin(); it != tlist->end(); ++it) {
249        cli->sendMsg(ResponseCode::TtyListResult, *it, false);
250    }
251
252    cli->sendMsg(ResponseCode::CommandOkay, "Ttys listed.", false);
253    return 0;
254}
255
256CommandListener::IpFwdCmd::IpFwdCmd() :
257                 NetdCommand("ipfwd") {
258}
259
260int CommandListener::IpFwdCmd::runCommand(SocketClient *cli,
261                                                      int argc, char **argv) {
262    int rc = 0;
263
264    if (argc < 2) {
265        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
266        return 0;
267    }
268
269    if (!strcmp(argv[1], "status")) {
270        char *tmp = NULL;
271
272        asprintf(&tmp, "Forwarding %s", (sTetherCtrl->getIpFwdEnabled() ? "enabled" : "disabled"));
273        cli->sendMsg(ResponseCode::IpFwdStatusResult, tmp, false);
274        free(tmp);
275        return 0;
276    } else if (!strcmp(argv[1], "enable")) {
277        rc = sTetherCtrl->setIpFwdEnabled(true);
278    } else if (!strcmp(argv[1], "disable")) {
279        rc = sTetherCtrl->setIpFwdEnabled(false);
280    } else {
281        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown ipfwd cmd", false);
282        return 0;
283    }
284
285    if (!rc) {
286        cli->sendMsg(ResponseCode::CommandOkay, "ipfwd operation succeeded", false);
287    } else {
288        cli->sendMsg(ResponseCode::OperationFailed, "ipfwd operation failed", true);
289    }
290
291    return 0;
292}
293
294CommandListener::TetherCmd::TetherCmd() :
295                 NetdCommand("tether") {
296}
297
298int CommandListener::TetherCmd::runCommand(SocketClient *cli,
299                                                      int argc, char **argv) {
300    int rc = 0;
301
302    if (argc < 2) {
303        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
304        return 0;
305    }
306
307    if (!strcmp(argv[1], "stop")) {
308        rc = sTetherCtrl->stopTethering();
309    } else if (!strcmp(argv[1], "status")) {
310        char *tmp = NULL;
311
312        asprintf(&tmp, "Tethering services %s",
313                 (sTetherCtrl->isTetheringStarted() ? "started" : "stopped"));
314        cli->sendMsg(ResponseCode::TetherStatusResult, tmp, false);
315        free(tmp);
316        return 0;
317    } else {
318        /*
319         * These commands take a minimum of 4 arguments
320         */
321        if (argc < 4) {
322            cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
323            return 0;
324        }
325
326        if (!strcmp(argv[1], "start")) {
327            if (argc % 2 == 1) {
328                cli->sendMsg(ResponseCode::CommandSyntaxError, "Bad number of arguments", false);
329                return 0;
330            }
331
332            int num_addrs = argc - 2;
333            int arg_index = 2;
334            int array_index = 0;
335            in_addr *addrs = (in_addr *)malloc(sizeof(in_addr) * num_addrs);
336            while (array_index < num_addrs) {
337                if (!inet_aton(argv[arg_index++], &(addrs[array_index++]))) {
338                    cli->sendMsg(ResponseCode::CommandParameterError, "Invalid address", false);
339                    free(addrs);
340                    return 0;
341                }
342            }
343            rc = sTetherCtrl->startTethering(num_addrs, addrs);
344            free(addrs);
345        } else if (!strcmp(argv[1], "interface")) {
346            if (!strcmp(argv[2], "add")) {
347                rc = sTetherCtrl->tetherInterface(argv[3]);
348            } else if (!strcmp(argv[2], "remove")) {
349                rc = sTetherCtrl->untetherInterface(argv[3]);
350            } else if (!strcmp(argv[2], "list")) {
351                InterfaceCollection *ilist = sTetherCtrl->getTetheredInterfaceList();
352                InterfaceCollection::iterator it;
353
354                for (it = ilist->begin(); it != ilist->end(); ++it) {
355                    cli->sendMsg(ResponseCode::TetherInterfaceListResult, *it, false);
356                }
357            } else {
358                cli->sendMsg(ResponseCode::CommandParameterError,
359                             "Unknown tether interface operation", false);
360                return 0;
361            }
362        } else if (!strcmp(argv[1], "dns")) {
363            if (!strcmp(argv[2], "set")) {
364                rc = sTetherCtrl->setDnsForwarders(&argv[3], argc - 3);
365            } else if (!strcmp(argv[2], "list")) {
366                NetAddressCollection *dlist = sTetherCtrl->getDnsForwarders();
367                NetAddressCollection::iterator it;
368
369                for (it = dlist->begin(); it != dlist->end(); ++it) {
370                    cli->sendMsg(ResponseCode::TetherDnsFwdTgtListResult, inet_ntoa(*it), false);
371                }
372            } else {
373                cli->sendMsg(ResponseCode::CommandParameterError,
374                             "Unknown tether interface operation", false);
375                return 0;
376            }
377        } else {
378            cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown tether cmd", false);
379            return 0;
380        }
381    }
382
383    if (!rc) {
384        cli->sendMsg(ResponseCode::CommandOkay, "Tether operation succeeded", false);
385    } else {
386        cli->sendMsg(ResponseCode::OperationFailed, "Tether operation failed", true);
387    }
388
389    return 0;
390}
391
392CommandListener::NatCmd::NatCmd() :
393                 NetdCommand("nat") {
394}
395
396int CommandListener::NatCmd::runCommand(SocketClient *cli,
397                                                      int argc, char **argv) {
398    int rc = 0;
399
400    if (argc < 3) {
401        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
402        return 0;
403    }
404
405    if (!strcmp(argv[1], "enable")) {
406        rc = sNatCtrl->enableNat(argv[2], argv[3]);
407    } else if (!strcmp(argv[1], "disable")) {
408        rc = sNatCtrl->disableNat(argv[2], argv[3]);
409    } else {
410        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown nat cmd", false);
411        return 0;
412    }
413
414    if (!rc) {
415        cli->sendMsg(ResponseCode::CommandOkay, "Nat operation succeeded", false);
416    } else {
417        cli->sendMsg(ResponseCode::OperationFailed, "Nat operation failed", true);
418    }
419
420    return 0;
421}
422
423CommandListener::PppdCmd::PppdCmd() :
424                 NetdCommand("pppd") {
425}
426
427int CommandListener::PppdCmd::runCommand(SocketClient *cli,
428                                                      int argc, char **argv) {
429    int rc = 0;
430
431    if (argc < 3) {
432        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
433        return 0;
434    }
435
436    if (!strcmp(argv[1], "attach")) {
437        struct in_addr l, r, dns1, dns2;
438
439        memset(&dns1, sizeof(struct in_addr), 0);
440        memset(&dns2, sizeof(struct in_addr), 0);
441
442        if (!inet_aton(argv[3], &l)) {
443            cli->sendMsg(ResponseCode::CommandParameterError, "Invalid local address", false);
444            return 0;
445        }
446        if (!inet_aton(argv[4], &r)) {
447            cli->sendMsg(ResponseCode::CommandParameterError, "Invalid remote address", false);
448            return 0;
449        }
450        if ((argc > 3) && (!inet_aton(argv[5], &dns1))) {
451            cli->sendMsg(ResponseCode::CommandParameterError, "Invalid dns1 address", false);
452            return 0;
453        }
454        if ((argc > 4) && (!inet_aton(argv[6], &dns2))) {
455            cli->sendMsg(ResponseCode::CommandParameterError, "Invalid dns2 address", false);
456            return 0;
457        }
458        rc = sPppCtrl->attachPppd(argv[2], l, r, dns1, dns2);
459    } else if (!strcmp(argv[1], "detach")) {
460        rc = sPppCtrl->detachPppd(argv[2]);
461    } else {
462        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown pppd cmd", false);
463        return 0;
464    }
465
466    if (!rc) {
467        cli->sendMsg(ResponseCode::CommandOkay, "Pppd operation succeeded", false);
468    } else {
469        cli->sendMsg(ResponseCode::OperationFailed, "Pppd operation failed", true);
470    }
471
472    return 0;
473}
474
475CommandListener::PanCmd::PanCmd() :
476                 NetdCommand("pan") {
477}
478
479int CommandListener::PanCmd::runCommand(SocketClient *cli,
480                                        int argc, char **argv) {
481    int rc = 0;
482
483    if (argc < 2) {
484        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
485        return 0;
486    }
487
488    if (!strcmp(argv[1], "start")) {
489        rc = sPanCtrl->startPan();
490    } else if (!strcmp(argv[1], "stop")) {
491        rc = sPanCtrl->stopPan();
492    } else if (!strcmp(argv[1], "status")) {
493        char *tmp = NULL;
494
495        asprintf(&tmp, "Pan services %s",
496                 (sPanCtrl->isPanStarted() ? "started" : "stopped"));
497        cli->sendMsg(ResponseCode::PanStatusResult, tmp, false);
498        free(tmp);
499        return 0;
500    } else {
501        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown pan cmd", false);
502        return 0;
503    }
504
505    if (!rc) {
506        cli->sendMsg(ResponseCode::CommandOkay, "Pan operation succeeded", false);
507    } else {
508        cli->sendMsg(ResponseCode::OperationFailed, "Pan operation failed", true);
509    }
510
511    return 0;
512}
513
514CommandListener::SoftapCmd::SoftapCmd() :
515                 NetdCommand("softap") {
516}
517
518int CommandListener::SoftapCmd::runCommand(SocketClient *cli,
519                                        int argc, char **argv) {
520    int rc = 0, flag = 0;
521
522    if (argc < 2) {
523        cli->sendMsg(ResponseCode::CommandSyntaxError, "Softap Missing argument", false);
524        return 0;
525    }
526
527    if (!strcmp(argv[1], "start")) {
528        rc = sSoftapCtrl->startDriver(argv[2]);
529    } else if (!strcmp(argv[1], "stop")) {
530        rc = sSoftapCtrl->stopDriver(argv[2]);
531    } else if (!strcmp(argv[1], "startap")) {
532        rc = sSoftapCtrl->startSoftap();
533    } else if (!strcmp(argv[1], "stopap")) {
534        rc = sSoftapCtrl->stopSoftap();
535    } else if (!strcmp(argv[1], "fwreload")) {
536        rc = sSoftapCtrl->fwReloadSoftap(argc, argv);
537    } else if (!strcmp(argv[1], "status")) {
538        char *tmp = NULL;
539
540        asprintf(&tmp, "Softap service %s",
541                 (sSoftapCtrl->isSoftapStarted() ? "started" : "stopped"));
542        cli->sendMsg(ResponseCode::SoftapStatusResult, tmp, false);
543        free(tmp);
544        return 0;
545    } else if (!strcmp(argv[1], "set")) {
546        rc = sSoftapCtrl->setSoftap(argc, argv);
547    } else {
548        cli->sendMsg(ResponseCode::CommandSyntaxError, "Softap Unknown cmd", false);
549        return 0;
550    }
551
552    if (!rc) {
553        cli->sendMsg(ResponseCode::CommandOkay, "Softap operation succeeded", false);
554    } else {
555        cli->sendMsg(ResponseCode::OperationFailed, "Softap operation failed", true);
556    }
557
558    return 0;
559}
560
561CommandListener::UsbCmd::UsbCmd() :
562                 NetdCommand("usb") {
563}
564
565int CommandListener::UsbCmd::runCommand(SocketClient *cli, int argc, char **argv) {
566    int rc = 0;
567
568    if (argc < 2) {
569        cli->sendMsg(ResponseCode::CommandSyntaxError, "Usb Missing argument", false);
570        return 0;
571    }
572
573    if (!strcmp(argv[1], "startrndis")) {
574        rc = sUsbCtrl->startRNDIS();
575    } else if (!strcmp(argv[1], "stoprndis")) {
576        rc = sUsbCtrl->stopRNDIS();
577    } else if (!strcmp(argv[1], "rndisstatus")) {
578        char *tmp = NULL;
579
580        asprintf(&tmp, "Usb RNDIS %s",
581                (sUsbCtrl->isRNDISStarted() ? "started" : "stopped"));
582        cli->sendMsg(ResponseCode::UsbRNDISStatusResult, tmp, false);
583        free(tmp);
584        return 0;
585    } else {
586        cli->sendMsg(ResponseCode::CommandSyntaxError, "Usb Unknown cmd", false);
587        return 0;
588    }
589
590    if (!rc) {
591        cli->sendMsg(ResponseCode::CommandOkay, "Usb operation succeeded", false);
592    } else {
593        cli->sendMsg(ResponseCode::OperationFailed, "Softap operation failed", true);
594    }
595
596    return 0;
597}
598