CommandListener.cpp revision e7b9422f0dc7a18041536c63efe74c7095496258
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            struct in_addr s, e;
328
329            if (!inet_aton(argv[2], &s)) {
330                cli->sendMsg(ResponseCode::CommandParameterError, "Invalid start address", false);
331                return 0;
332            }
333            if (!inet_aton(argv[3], &e)) {
334                cli->sendMsg(ResponseCode::CommandParameterError, "Invalid end address", false);
335                return 0;
336            }
337            rc = sTetherCtrl->startTethering(s, e);
338        } else if (!strcmp(argv[1], "interface")) {
339            if (!strcmp(argv[2], "add")) {
340                rc = sTetherCtrl->tetherInterface(argv[3]);
341            } else if (!strcmp(argv[2], "remove")) {
342                rc = sTetherCtrl->untetherInterface(argv[3]);
343            } else if (!strcmp(argv[2], "list")) {
344                InterfaceCollection *ilist = sTetherCtrl->getTetheredInterfaceList();
345                InterfaceCollection::iterator it;
346
347                for (it = ilist->begin(); it != ilist->end(); ++it) {
348                    cli->sendMsg(ResponseCode::TetherInterfaceListResult, *it, false);
349                }
350            } else {
351                cli->sendMsg(ResponseCode::CommandParameterError,
352                             "Unknown tether interface operation", false);
353                return 0;
354            }
355        } else if (!strcmp(argv[1], "dns")) {
356            if (!strcmp(argv[2], "set")) {
357                rc = sTetherCtrl->setDnsForwarders(&argv[3], argc - 3);
358            } else if (!strcmp(argv[2], "list")) {
359                NetAddressCollection *dlist = sTetherCtrl->getDnsForwarders();
360                NetAddressCollection::iterator it;
361
362                for (it = dlist->begin(); it != dlist->end(); ++it) {
363                    cli->sendMsg(ResponseCode::TetherDnsFwdTgtListResult, inet_ntoa(*it), false);
364                }
365            } else {
366                cli->sendMsg(ResponseCode::CommandParameterError,
367                             "Unknown tether interface operation", false);
368                return 0;
369            }
370        } else {
371            cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown tether cmd", false);
372            return 0;
373        }
374    }
375
376    if (!rc) {
377        cli->sendMsg(ResponseCode::CommandOkay, "Tether operation succeeded", false);
378    } else {
379        cli->sendMsg(ResponseCode::OperationFailed, "Tether operation failed", true);
380    }
381
382    return 0;
383}
384
385CommandListener::NatCmd::NatCmd() :
386                 NetdCommand("nat") {
387}
388
389int CommandListener::NatCmd::runCommand(SocketClient *cli,
390                                                      int argc, char **argv) {
391    int rc = 0;
392
393    if (argc < 3) {
394        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
395        return 0;
396    }
397
398    if (!strcmp(argv[1], "enable")) {
399        rc = sNatCtrl->enableNat(argv[2], argv[3]);
400    } else if (!strcmp(argv[1], "disable")) {
401        rc = sNatCtrl->disableNat(argv[2], argv[3]);
402    } else {
403        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown nat cmd", false);
404        return 0;
405    }
406
407    if (!rc) {
408        cli->sendMsg(ResponseCode::CommandOkay, "Nat operation succeeded", false);
409    } else {
410        cli->sendMsg(ResponseCode::OperationFailed, "Nat operation failed", true);
411    }
412
413    return 0;
414}
415
416CommandListener::PppdCmd::PppdCmd() :
417                 NetdCommand("pppd") {
418}
419
420int CommandListener::PppdCmd::runCommand(SocketClient *cli,
421                                                      int argc, char **argv) {
422    int rc = 0;
423
424    if (argc < 3) {
425        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
426        return 0;
427    }
428
429    if (!strcmp(argv[1], "attach")) {
430        struct in_addr l, r, dns1, dns2;
431
432        memset(&dns1, sizeof(struct in_addr), 0);
433        memset(&dns2, sizeof(struct in_addr), 0);
434
435        if (!inet_aton(argv[3], &l)) {
436            cli->sendMsg(ResponseCode::CommandParameterError, "Invalid local address", false);
437            return 0;
438        }
439        if (!inet_aton(argv[4], &r)) {
440            cli->sendMsg(ResponseCode::CommandParameterError, "Invalid remote address", false);
441            return 0;
442        }
443        if ((argc > 3) && (!inet_aton(argv[5], &dns1))) {
444            cli->sendMsg(ResponseCode::CommandParameterError, "Invalid dns1 address", false);
445            return 0;
446        }
447        if ((argc > 4) && (!inet_aton(argv[6], &dns2))) {
448            cli->sendMsg(ResponseCode::CommandParameterError, "Invalid dns2 address", false);
449            return 0;
450        }
451        rc = sPppCtrl->attachPppd(argv[2], l, r, dns1, dns2);
452    } else if (!strcmp(argv[1], "detach")) {
453        rc = sPppCtrl->detachPppd(argv[2]);
454    } else {
455        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown pppd cmd", false);
456        return 0;
457    }
458
459    if (!rc) {
460        cli->sendMsg(ResponseCode::CommandOkay, "Pppd operation succeeded", false);
461    } else {
462        cli->sendMsg(ResponseCode::OperationFailed, "Pppd operation failed", true);
463    }
464
465    return 0;
466}
467
468CommandListener::PanCmd::PanCmd() :
469                 NetdCommand("pan") {
470}
471
472int CommandListener::PanCmd::runCommand(SocketClient *cli,
473                                        int argc, char **argv) {
474    int rc = 0;
475
476    if (argc < 2) {
477        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
478        return 0;
479    }
480
481    if (!strcmp(argv[1], "start")) {
482        rc = sPanCtrl->startPan();
483    } else if (!strcmp(argv[1], "stop")) {
484        rc = sPanCtrl->stopPan();
485    } else if (!strcmp(argv[1], "status")) {
486        char *tmp = NULL;
487
488        asprintf(&tmp, "Pan services %s",
489                 (sPanCtrl->isPanStarted() ? "started" : "stopped"));
490        cli->sendMsg(ResponseCode::PanStatusResult, tmp, false);
491        free(tmp);
492        return 0;
493    } else {
494        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown pan cmd", false);
495        return 0;
496    }
497
498    if (!rc) {
499        cli->sendMsg(ResponseCode::CommandOkay, "Pan operation succeeded", false);
500    } else {
501        cli->sendMsg(ResponseCode::OperationFailed, "Pan operation failed", true);
502    }
503
504    return 0;
505}
506
507CommandListener::SoftapCmd::SoftapCmd() :
508                 NetdCommand("softap") {
509}
510
511int CommandListener::SoftapCmd::runCommand(SocketClient *cli,
512                                        int argc, char **argv) {
513    int rc = 0;
514
515    if (argc < 2) {
516        cli->sendMsg(ResponseCode::CommandSyntaxError, "Softap Missing argument", false);
517        return 0;
518    }
519
520    if (!strcmp(argv[1], "start")) {
521        rc = sSoftapCtrl->startSoftap();
522    } else if (!strcmp(argv[1], "stop")) {
523        rc = sSoftapCtrl->stopSoftap();
524    } else if (!strcmp(argv[1], "status")) {
525        char *tmp = NULL;
526
527        asprintf(&tmp, "Softap service %s",
528                 (sSoftapCtrl->isSoftapStarted() ? "started" : "stopped"));
529        cli->sendMsg(ResponseCode::SoftapStatusResult, tmp, false);
530        free(tmp);
531        return 0;
532    } else if (!strcmp(argv[1], "set")) {
533        rc = sSoftapCtrl->setSoftap(argc, argv);
534    } else {
535        cli->sendMsg(ResponseCode::CommandSyntaxError, "Softap Unknown cmd", false);
536        return 0;
537    }
538
539    if (!rc) {
540        cli->sendMsg(ResponseCode::CommandOkay, "Softap operation succeeded", false);
541    } else {
542        cli->sendMsg(ResponseCode::OperationFailed, "Softap operation failed", true);
543    }
544
545    return 0;
546}
547
548CommandListener::UsbCmd::UsbCmd() :
549                 NetdCommand("usb") {
550}
551
552int CommandListener::UsbCmd::runCommand(SocketClient *cli, int argc, char **argv) {
553    int rc = 0;
554
555    if (argc < 2) {
556        cli->sendMsg(ResponseCode::CommandSyntaxError, "Usb Missing argument", false);
557        return 0;
558    }
559
560    if (!strcmp(argv[1], "startrndis")) {
561        rc = sUsbCtrl->startRNDIS();
562    } else if (!strcmp(argv[1], "stoprndis")) {
563        rc = sUsbCtrl->stopRNDIS();
564    } else if (!strcmp(argv[1], "rndisstatus")) {
565        char *tmp = NULL;
566
567        asprintf(&tmp, "Usb RNDIS %s",
568                (sUsbCtrl->isRNDISStarted() ? "started" : "stopped"));
569        cli->sendMsg(ResponseCode::UsbRNDISStatusResult, tmp, false);
570        free(tmp);
571        return 0;
572    } else {
573        cli->sendMsg(ResponseCode::CommandSyntaxError, "Usb Unknown cmd", false);
574        return 0;
575    }
576
577    if (!rc) {
578        cli->sendMsg(ResponseCode::CommandOkay, "Usb operation succeeded", false);
579    } else {
580        cli->sendMsg(ResponseCode::OperationFailed, "Softap operation failed", true);
581    }
582
583    return 0;
584}
585