CommandListener.cpp revision 3e6ba3ce1abda6071d5b01f53ca6039bb7b5e2d3
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]\n", 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            if (argc < 5) {
158                cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
159                return 0;
160            }
161
162            struct in_addr addr, mask;
163            unsigned flags = 0;
164
165            if (!inet_aton(argv[3], &addr)) {
166                cli->sendMsg(ResponseCode::CommandParameterError, "Invalid address", false);
167                return 0;
168            }
169
170            if (!inet_aton(argv[4], &mask)) {
171                cli->sendMsg(ResponseCode::CommandParameterError, "Invalid netmask", false);
172                return 0;
173            }
174
175            ifc_init();
176            if (ifc_set_addr(argv[2], addr.s_addr)) {
177                cli->sendMsg(ResponseCode::OperationFailed, "Failed to set address", true);
178                return 0;
179            }
180
181            if (ifc_set_mask(argv[2], mask.s_addr)) {
182                cli->sendMsg(ResponseCode::OperationFailed, "Failed to set netmask", true);
183                return 0;
184            }
185
186            /* Process flags */
187            for (int i = 5; i < argc; i++) {
188                if (!strcmp(argv[i], "up")) {
189                    if (ifc_up(argv[2])) {
190                        LOGE("Error upping interface");
191                        cli->sendMsg(ResponseCode::OperationFailed, "Failed to up interface", true);
192                        return 0;
193                    }
194                } else if (!strcmp(argv[i], "down")) {
195                    if (ifc_down(argv[2])) {
196                        LOGE("Error downing interface");
197                        cli->sendMsg(ResponseCode::OperationFailed, "Failed to down interface", true);
198                        return 0;
199                    }
200                } else {
201                    cli->sendMsg(ResponseCode::CommandParameterError, "Flag unsupported", false);
202                    return 0;
203                }
204            }
205            cli->sendMsg(ResponseCode::CommandOkay, "Interface configuration set", false);
206            return 0;
207        } else {
208            cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown interface cmd", false);
209            return 0;
210        }
211    }
212    return 0;
213}
214
215CommandListener::ListTtysCmd::ListTtysCmd() :
216                 NetdCommand("list_ttys") {
217}
218
219int CommandListener::ListTtysCmd::runCommand(SocketClient *cli,
220                                             int argc, char **argv) {
221    TtyCollection *tlist = sPppCtrl->getTtyList();
222    TtyCollection::iterator it;
223
224    for (it = tlist->begin(); it != tlist->end(); ++it) {
225        cli->sendMsg(ResponseCode::TtyListResult, *it, false);
226    }
227
228    cli->sendMsg(ResponseCode::CommandOkay, "Ttys listed.", false);
229    return 0;
230}
231
232CommandListener::IpFwdCmd::IpFwdCmd() :
233                 NetdCommand("ipfwd") {
234}
235
236int CommandListener::IpFwdCmd::runCommand(SocketClient *cli,
237                                                      int argc, char **argv) {
238    int rc = 0;
239
240    if (argc < 2) {
241        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
242        return 0;
243    }
244
245    if (!strcmp(argv[1], "status")) {
246        char *tmp = NULL;
247
248        asprintf(&tmp, "Forwarding %s", (sTetherCtrl->getIpFwdEnabled() ? "enabled" : "disabled"));
249        cli->sendMsg(ResponseCode::IpFwdStatusResult, tmp, false);
250        free(tmp);
251        return 0;
252    } else if (!strcmp(argv[1], "enable")) {
253        rc = sTetherCtrl->setIpFwdEnabled(true);
254    } else if (!strcmp(argv[1], "disable")) {
255        rc = sTetherCtrl->setIpFwdEnabled(false);
256    } else {
257        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown ipfwd cmd", false);
258        return 0;
259    }
260
261    if (!rc) {
262        cli->sendMsg(ResponseCode::CommandOkay, "ipfwd operation succeeded", false);
263    } else {
264        cli->sendMsg(ResponseCode::OperationFailed, "ipfwd operation failed", true);
265    }
266
267    return 0;
268}
269
270CommandListener::TetherCmd::TetherCmd() :
271                 NetdCommand("tether") {
272}
273
274int CommandListener::TetherCmd::runCommand(SocketClient *cli,
275                                                      int argc, char **argv) {
276    int rc = 0;
277
278    if (argc < 2) {
279        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
280        return 0;
281    }
282
283    if (!strcmp(argv[1], "stop")) {
284        rc = sTetherCtrl->stopTethering();
285    } else if (!strcmp(argv[1], "status")) {
286        char *tmp = NULL;
287
288        asprintf(&tmp, "Tethering services %s",
289                 (sTetherCtrl->isTetheringStarted() ? "started" : "stopped"));
290        cli->sendMsg(ResponseCode::TetherStatusResult, tmp, false);
291        free(tmp);
292        return 0;
293    } else {
294        /*
295         * These commands take a minimum of 4 arguments
296         */
297        if (argc < 4) {
298            cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
299            return 0;
300        }
301
302        if (!strcmp(argv[1], "start")) {
303            struct in_addr s, e;
304
305            if (!inet_aton(argv[2], &s)) {
306                cli->sendMsg(ResponseCode::CommandParameterError, "Invalid start address", false);
307                return 0;
308            }
309            if (!inet_aton(argv[3], &e)) {
310                cli->sendMsg(ResponseCode::CommandParameterError, "Invalid end address", false);
311                return 0;
312            }
313            rc = sTetherCtrl->startTethering(s, e);
314        } else if (!strcmp(argv[1], "interface")) {
315            if (!strcmp(argv[2], "add")) {
316                rc = sTetherCtrl->tetherInterface(argv[3]);
317            } else if (!strcmp(argv[2], "remove")) {
318                rc = sTetherCtrl->untetherInterface(argv[3]);
319            } else if (!strcmp(argv[2], "list")) {
320                InterfaceCollection *ilist = sTetherCtrl->getTetheredInterfaceList();
321                InterfaceCollection::iterator it;
322
323                for (it = ilist->begin(); it != ilist->end(); ++it) {
324                    cli->sendMsg(ResponseCode::TetherInterfaceListResult, *it, false);
325                }
326            } else {
327                cli->sendMsg(ResponseCode::CommandParameterError,
328                             "Unknown tether interface operation", false);
329                return 0;
330            }
331        } else if (!strcmp(argv[1], "dns")) {
332            if (!strcmp(argv[2], "set")) {
333                rc = sTetherCtrl->setDnsForwarders(&argv[3], argc - 3);
334            } else if (!strcmp(argv[2], "list")) {
335                NetAddressCollection *dlist = sTetherCtrl->getDnsForwarders();
336                NetAddressCollection::iterator it;
337
338                for (it = dlist->begin(); it != dlist->end(); ++it) {
339                    cli->sendMsg(ResponseCode::TetherDnsFwdTgtListResult, inet_ntoa(*it), false);
340                }
341            } else {
342                cli->sendMsg(ResponseCode::CommandParameterError,
343                             "Unknown tether interface operation", false);
344                return 0;
345            }
346        } else {
347            cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown tether cmd", false);
348            return 0;
349        }
350    }
351
352    if (!rc) {
353        cli->sendMsg(ResponseCode::CommandOkay, "Tether operation succeeded", false);
354    } else {
355        cli->sendMsg(ResponseCode::OperationFailed, "Tether operation failed", true);
356    }
357
358    return 0;
359}
360
361CommandListener::NatCmd::NatCmd() :
362                 NetdCommand("nat") {
363}
364
365int CommandListener::NatCmd::runCommand(SocketClient *cli,
366                                                      int argc, char **argv) {
367    int rc = 0;
368
369    if (argc < 3) {
370        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
371        return 0;
372    }
373
374    if (!strcmp(argv[1], "enable")) {
375        rc = sNatCtrl->enableNat(argv[2], argv[3]);
376    } else if (!strcmp(argv[1], "disable")) {
377        rc = sNatCtrl->disableNat(argv[2], argv[3]);
378    } else {
379        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown nat cmd", false);
380        return 0;
381    }
382
383    if (!rc) {
384        cli->sendMsg(ResponseCode::CommandOkay, "Nat operation succeeded", false);
385    } else {
386        cli->sendMsg(ResponseCode::OperationFailed, "Nat operation failed", true);
387    }
388
389    return 0;
390}
391
392CommandListener::PppdCmd::PppdCmd() :
393                 NetdCommand("pppd") {
394}
395
396int CommandListener::PppdCmd::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], "attach")) {
406        struct in_addr l, r, dns1, dns2;
407
408        memset(&dns1, sizeof(struct in_addr), 0);
409        memset(&dns2, sizeof(struct in_addr), 0);
410
411        if (!inet_aton(argv[3], &l)) {
412            cli->sendMsg(ResponseCode::CommandParameterError, "Invalid local address", false);
413            return 0;
414        }
415        if (!inet_aton(argv[4], &r)) {
416            cli->sendMsg(ResponseCode::CommandParameterError, "Invalid remote address", false);
417            return 0;
418        }
419        if ((argc > 3) && (!inet_aton(argv[5], &dns1))) {
420            cli->sendMsg(ResponseCode::CommandParameterError, "Invalid dns1 address", false);
421            return 0;
422        }
423        if ((argc > 4) && (!inet_aton(argv[6], &dns2))) {
424            cli->sendMsg(ResponseCode::CommandParameterError, "Invalid dns2 address", false);
425            return 0;
426        }
427        rc = sPppCtrl->attachPppd(argv[2], l, r, dns1, dns2);
428    } else if (!strcmp(argv[1], "detach")) {
429        rc = sPppCtrl->detachPppd(argv[2]);
430    } else {
431        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown pppd cmd", false);
432        return 0;
433    }
434
435    if (!rc) {
436        cli->sendMsg(ResponseCode::CommandOkay, "Pppd operation succeeded", false);
437    } else {
438        cli->sendMsg(ResponseCode::OperationFailed, "Pppd operation failed", true);
439    }
440
441    return 0;
442}
443
444CommandListener::PanCmd::PanCmd() :
445                 NetdCommand("pan") {
446}
447
448int CommandListener::PanCmd::runCommand(SocketClient *cli,
449                                        int argc, char **argv) {
450    int rc = 0;
451
452    if (argc < 2) {
453        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
454        return 0;
455    }
456
457    if (!strcmp(argv[1], "start")) {
458        rc = sPanCtrl->startPan();
459    } else if (!strcmp(argv[1], "stop")) {
460        rc = sPanCtrl->stopPan();
461    } else if (!strcmp(argv[1], "status")) {
462        char *tmp = NULL;
463
464        asprintf(&tmp, "Pan services %s",
465                 (sPanCtrl->isPanStarted() ? "started" : "stopped"));
466        cli->sendMsg(ResponseCode::PanStatusResult, tmp, false);
467        free(tmp);
468        return 0;
469    } else {
470        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown pan cmd", false);
471        return 0;
472    }
473
474    if (!rc) {
475        cli->sendMsg(ResponseCode::CommandOkay, "Pan operation succeeded", false);
476    } else {
477        cli->sendMsg(ResponseCode::OperationFailed, "Pan operation failed", true);
478    }
479
480    return 0;
481}
482
483CommandListener::SoftapCmd::SoftapCmd() :
484                 NetdCommand("softap") {
485}
486
487int CommandListener::SoftapCmd::runCommand(SocketClient *cli,
488                                        int argc, char **argv) {
489    int rc = 0;
490
491    if (argc < 2) {
492        cli->sendMsg(ResponseCode::CommandSyntaxError, "Softap Missing argument", false);
493        return 0;
494    }
495
496    if (!strcmp(argv[1], "start")) {
497        rc = sSoftapCtrl->startSoftap();
498    } else if (!strcmp(argv[1], "stop")) {
499        rc = sSoftapCtrl->stopSoftap();
500    } else if (!strcmp(argv[1], "status")) {
501        char *tmp = NULL;
502
503        asprintf(&tmp, "Softap service %s",
504                 (sSoftapCtrl->isSoftapStarted() ? "started" : "stopped"));
505        cli->sendMsg(ResponseCode::SoftapStatusResult, tmp, false);
506        free(tmp);
507        return 0;
508    } else if (!strcmp(argv[1], "set")) {
509        rc = sSoftapCtrl->setSoftap(argc, argv);
510    } else {
511        cli->sendMsg(ResponseCode::CommandSyntaxError, "Softap Unknown cmd", false);
512        return 0;
513    }
514
515    if (!rc) {
516        cli->sendMsg(ResponseCode::CommandOkay, "Softap operation succeeded", false);
517    } else {
518        cli->sendMsg(ResponseCode::OperationFailed, "Softap operation failed", true);
519    }
520
521    return 0;
522}
523
524CommandListener::UsbCmd::UsbCmd() :
525                 NetdCommand("usb") {
526}
527
528int CommandListener::UsbCmd::runCommand(SocketClient *cli, int argc, char **argv) {
529    int rc = 0;
530
531    if (argc < 2) {
532        cli->sendMsg(ResponseCode::CommandSyntaxError, "Usb Missing argument", false);
533        return 0;
534    }
535
536    if (!strcmp(argv[1], "startrndis")) {
537        rc = sUsbCtrl->startRNDIS();
538    } else if (!strcmp(argv[1], "stoprndis")) {
539        rc = sUsbCtrl->stopRNDIS();
540    } else if (!strcmp(argv[1], "rndisstatus")) {
541        char *tmp = NULL;
542
543        asprintf(&tmp, "Usb RNDIS %s",
544                (sUsbCtrl->isRNDISStarted() ? "started" : "stopped"));
545        cli->sendMsg(ResponseCode::UsbRNDISStatusResult, tmp, false);
546        free(tmp);
547        return 0;
548    } else {
549        cli->sendMsg(ResponseCode::CommandSyntaxError, "Usb Unknown cmd", false);
550        return 0;
551    }
552
553    if (!rc) {
554        cli->sendMsg(ResponseCode::CommandOkay, "Usb operation succeeded", false);
555    } else {
556        cli->sendMsg(ResponseCode::OperationFailed, "Softap operation failed", true);
557    }
558
559    return 0;
560}
561