CommandListener.cpp revision 01fed783828b592cda3b774deea4099a9e690e3d
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;
47
48CommandListener::CommandListener() :
49                 FrameworkListener("netd") {
50    registerCmd(new InterfaceCmd());
51    registerCmd(new IpFwdCmd());
52    registerCmd(new TetherCmd());
53    registerCmd(new NatCmd());
54    registerCmd(new ListTtysCmd());
55    registerCmd(new PppdCmd());
56    registerCmd(new PanCmd());
57
58    if (!sTetherCtrl)
59        sTetherCtrl = new TetherController();
60    if (!sNatCtrl)
61        sNatCtrl = new NatController();
62    if (!sPppCtrl)
63        sPppCtrl = new PppController();
64    if (!sPanCtrl)
65        sPanCtrl = new PanController();
66}
67
68CommandListener::InterfaceCmd::InterfaceCmd() :
69                 NetdCommand("interface") {
70}
71
72int CommandListener::InterfaceCmd::runCommand(SocketClient *cli,
73                                                      int argc, char **argv) {
74    if (argc < 2) {
75        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
76        return 0;
77    }
78
79    if (!strcmp(argv[1], "list")) {
80        DIR *d;
81        struct dirent *de;
82
83        if (!(d = opendir("/sys/class/net"))) {
84            cli->sendMsg(ResponseCode::OperationFailed, "Failed to open sysfs dir", true);
85            return 0;
86        }
87
88        while((de = readdir(d))) {
89            if (de->d_name[0] == '.')
90                continue;
91            cli->sendMsg(ResponseCode::InterfaceListResult, de->d_name, false);
92        }
93        closedir(d);
94        cli->sendMsg(ResponseCode::CommandOkay, "Interface list completed", false);
95        return 0;
96    } else {
97        /*
98         * These commands take a minimum of 3 arguments
99         */
100        if (argc < 3) {
101            cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
102            return 0;
103        }
104        if (!strcmp(argv[1], "getcfg")) {
105            struct in_addr addr, mask;
106            unsigned char hwaddr[6];
107            unsigned flags = 0;
108
109            ifc_init();
110            memset(hwaddr, 0, sizeof(hwaddr));
111
112            if (ifc_get_info(argv[2], &addr.s_addr, &mask.s_addr, &flags)) {
113                cli->sendMsg(ResponseCode::OperationFailed, "Interface not found", true);
114                return 0;
115            }
116
117            if (ifc_get_hwaddr(argv[2], (void *) hwaddr)) {
118                LOGW("Failed to retrieve HW addr for %s (%s)", argv[2], strerror(errno));
119            }
120
121            char *addr_s = strdup(inet_ntoa(addr));
122            char *mask_s = strdup(inet_ntoa(mask));
123            const char *updown, *brdcst, *loopbk, *ppp, *running, *multi;
124
125            updown =  (flags & IFF_UP)           ? "up" : "down";
126            brdcst =  (flags & IFF_BROADCAST)    ? " broadcast" : "";
127            loopbk =  (flags & IFF_LOOPBACK)     ? " loopback" : "";
128            ppp =     (flags & IFF_POINTOPOINT)  ? " point-to-point" : "";
129            running = (flags & IFF_RUNNING)      ? " running" : "";
130            multi =   (flags & IFF_MULTICAST)    ? " multicast" : "";
131
132            char *flag_s;
133
134            asprintf(&flag_s, "[%s%s%s%s%s%s]\n", updown, brdcst, loopbk, ppp, running, multi);
135
136            char *msg = NULL;
137            asprintf(&msg, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x %s %s %s",
138                     hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5],
139                     addr_s, mask_s, flag_s);
140
141            cli->sendMsg(ResponseCode::InterfaceGetCfgResult, msg, false);
142
143            free(addr_s);
144            free(mask_s);
145            free(flag_s);
146            free(msg);
147            return 0;
148        } else if (!strcmp(argv[1], "setcfg")) {
149            if (argc < 5) {
150                cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
151                return 0;
152            }
153
154            struct in_addr addr, mask;
155            unsigned flags = 0;
156
157            if (!inet_aton(argv[3], &addr)) {
158                cli->sendMsg(ResponseCode::CommandParameterError, "Invalid address", false);
159                return 0;
160            }
161
162            if (!inet_aton(argv[4], &mask)) {
163                cli->sendMsg(ResponseCode::CommandParameterError, "Invalid netmask", false);
164                return 0;
165            }
166
167            ifc_init();
168            if (ifc_set_addr(argv[2], addr.s_addr)) {
169                cli->sendMsg(ResponseCode::OperationFailed, "Failed to set address", true);
170                return 0;
171            }
172
173            if (ifc_set_mask(argv[2], mask.s_addr)) {
174                cli->sendMsg(ResponseCode::OperationFailed, "Failed to set netmask", true);
175                return 0;
176            }
177
178            /* Process flags */
179            for (int i = 5; i < argc; i++) {
180                if (!strcmp(argv[i], "up")) {
181                    if (ifc_up(argv[2])) {
182                        LOGE("Error upping interface");
183                        cli->sendMsg(ResponseCode::OperationFailed, "Failed to up interface", true);
184                        return 0;
185                    }
186                } else if (!strcmp(argv[i], "down")) {
187                    if (ifc_down(argv[2])) {
188                        LOGE("Error downing interface");
189                        cli->sendMsg(ResponseCode::OperationFailed, "Failed to down interface", true);
190                        return 0;
191                    }
192                } else {
193                    cli->sendMsg(ResponseCode::CommandParameterError, "Flag unsupported", false);
194                    return 0;
195                }
196            }
197            cli->sendMsg(ResponseCode::CommandOkay, "Interface configuration set", false);
198            return 0;
199        } else {
200            cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown interface cmd", false);
201            return 0;
202        }
203    }
204    return 0;
205}
206
207CommandListener::ListTtysCmd::ListTtysCmd() :
208                 NetdCommand("list_ttys") {
209}
210
211int CommandListener::ListTtysCmd::runCommand(SocketClient *cli,
212                                             int argc, char **argv) {
213    TtyCollection *tlist = sPppCtrl->getTtyList();
214    TtyCollection::iterator it;
215
216    for (it = tlist->begin(); it != tlist->end(); ++it) {
217        cli->sendMsg(ResponseCode::TtyListResult, *it, false);
218    }
219
220    cli->sendMsg(ResponseCode::CommandOkay, "Ttys listed.", false);
221    return 0;
222}
223
224CommandListener::IpFwdCmd::IpFwdCmd() :
225                 NetdCommand("ipfwd") {
226}
227
228int CommandListener::IpFwdCmd::runCommand(SocketClient *cli,
229                                                      int argc, char **argv) {
230    int rc = 0;
231
232    if (argc < 2) {
233        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
234        return 0;
235    }
236
237    if (!strcmp(argv[1], "status")) {
238        char *tmp = NULL;
239
240        asprintf(&tmp, "Forwarding %s", (sTetherCtrl->getIpFwdEnabled() ? "enabled" : "disabled"));
241        cli->sendMsg(ResponseCode::IpFwdStatusResult, tmp, false);
242        free(tmp);
243        return 0;
244    } else if (!strcmp(argv[1], "enable")) {
245        rc = sTetherCtrl->setIpFwdEnabled(true);
246    } else if (!strcmp(argv[1], "disable")) {
247        rc = sTetherCtrl->setIpFwdEnabled(false);
248    } else {
249        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown ipfwd cmd", false);
250        return 0;
251    }
252
253    if (!rc) {
254        cli->sendMsg(ResponseCode::CommandOkay, "ipfwd operation succeeded", false);
255    } else {
256        cli->sendMsg(ResponseCode::OperationFailed, "ipfwd operation failed", true);
257    }
258
259    return 0;
260}
261
262CommandListener::TetherCmd::TetherCmd() :
263                 NetdCommand("tether") {
264}
265
266int CommandListener::TetherCmd::runCommand(SocketClient *cli,
267                                                      int argc, char **argv) {
268    int rc = 0;
269
270    if (argc < 2) {
271        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
272        return 0;
273    }
274
275    if (!strcmp(argv[1], "stop")) {
276        rc = sTetherCtrl->stopTethering();
277    } else if (!strcmp(argv[1], "status")) {
278        char *tmp = NULL;
279
280        asprintf(&tmp, "Tethering services %s",
281                 (sTetherCtrl->isTetheringStarted() ? "started" : "stopped"));
282        cli->sendMsg(ResponseCode::TetherStatusResult, tmp, false);
283        free(tmp);
284        return 0;
285    } else {
286        /*
287         * These commands take a minimum of 4 arguments
288         */
289        if (argc < 4) {
290            cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
291            return 0;
292        }
293
294        if (!strcmp(argv[1], "start")) {
295            struct in_addr s, e;
296
297            if (!inet_aton(argv[2], &s)) {
298                cli->sendMsg(ResponseCode::CommandParameterError, "Invalid start address", false);
299                return 0;
300            }
301            if (!inet_aton(argv[3], &e)) {
302                cli->sendMsg(ResponseCode::CommandParameterError, "Invalid end address", false);
303                return 0;
304            }
305            rc = sTetherCtrl->startTethering(s, e);
306        } else if (!strcmp(argv[1], "interface")) {
307            if (!strcmp(argv[2], "add")) {
308                rc = sTetherCtrl->tetherInterface(argv[3]);
309            } else if (!strcmp(argv[2], "remove")) {
310                rc = sTetherCtrl->untetherInterface(argv[3]);
311            } else if (!strcmp(argv[2], "list")) {
312                InterfaceCollection *ilist = sTetherCtrl->getTetheredInterfaceList();
313                InterfaceCollection::iterator it;
314
315                for (it = ilist->begin(); it != ilist->end(); ++it) {
316                    cli->sendMsg(ResponseCode::TetherInterfaceListResult, *it, false);
317                }
318            } else {
319                cli->sendMsg(ResponseCode::CommandParameterError,
320                             "Unknown tether interface operation", false);
321                return 0;
322            }
323        } else if (!strcmp(argv[1], "dns")) {
324            if (!strcmp(argv[2], "set")) {
325                rc = sTetherCtrl->setDnsForwarders(&argv[3], argc - 3);
326            } else if (!strcmp(argv[2], "list")) {
327                NetAddressCollection *dlist = sTetherCtrl->getDnsForwarders();
328                NetAddressCollection::iterator it;
329
330                for (it = dlist->begin(); it != dlist->end(); ++it) {
331                    cli->sendMsg(ResponseCode::TetherDnsFwdTgtListResult, inet_ntoa(*it), false);
332                }
333            } else {
334                cli->sendMsg(ResponseCode::CommandParameterError,
335                             "Unknown tether interface operation", false);
336                return 0;
337            }
338        } else {
339            cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown tether cmd", false);
340            return 0;
341        }
342    }
343
344    if (!rc) {
345        cli->sendMsg(ResponseCode::CommandOkay, "Tether operation succeeded", false);
346    } else {
347        cli->sendMsg(ResponseCode::OperationFailed, "Tether operation failed", true);
348    }
349
350    return 0;
351}
352
353CommandListener::NatCmd::NatCmd() :
354                 NetdCommand("nat") {
355}
356
357int CommandListener::NatCmd::runCommand(SocketClient *cli,
358                                                      int argc, char **argv) {
359    int rc = 0;
360
361    if (argc < 3) {
362        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
363        return 0;
364    }
365
366    if (!strcmp(argv[1], "enable")) {
367        rc = sNatCtrl->enableNat(argv[2], argv[3]);
368    } else if (!strcmp(argv[1], "disable")) {
369        rc = sNatCtrl->disableNat(argv[2], argv[3]);
370    } else {
371        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown nat cmd", false);
372        return 0;
373    }
374
375    if (!rc) {
376        cli->sendMsg(ResponseCode::CommandOkay, "Nat operation succeeded", false);
377    } else {
378        cli->sendMsg(ResponseCode::OperationFailed, "Nat operation failed", true);
379    }
380
381    return 0;
382}
383
384CommandListener::PppdCmd::PppdCmd() :
385                 NetdCommand("pppd") {
386}
387
388int CommandListener::PppdCmd::runCommand(SocketClient *cli,
389                                                      int argc, char **argv) {
390    int rc = 0;
391
392    if (argc < 3) {
393        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
394        return 0;
395    }
396
397    if (!strcmp(argv[1], "attach")) {
398        struct in_addr l, r;
399
400        if (!inet_aton(argv[3], &l)) {
401            cli->sendMsg(ResponseCode::CommandParameterError, "Invalid local address", false);
402            return 0;
403        }
404        if (!inet_aton(argv[4], &r)) {
405            cli->sendMsg(ResponseCode::CommandParameterError, "Invalid remote address", false);
406            return 0;
407        }
408        rc = sPppCtrl->attachPppd(argv[2], l, r);
409    } else if (!strcmp(argv[1], "detach")) {
410        rc = sPppCtrl->detachPppd(argv[2]);
411    } else {
412        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown pppd cmd", false);
413        return 0;
414    }
415
416    if (!rc) {
417        cli->sendMsg(ResponseCode::CommandOkay, "Pppd operation succeeded", false);
418    } else {
419        cli->sendMsg(ResponseCode::OperationFailed, "Pppd operation failed", true);
420    }
421
422    return 0;
423}
424
425CommandListener::PanCmd::PanCmd() :
426                 NetdCommand("pan") {
427}
428
429int CommandListener::PanCmd::runCommand(SocketClient *cli,
430                                        int argc, char **argv) {
431    int rc = 0;
432
433    if (argc < 2) {
434        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
435        return 0;
436    }
437
438    if (!strcmp(argv[1], "start")) {
439        rc = sPanCtrl->startPan();
440    } else if (!strcmp(argv[1], "stop")) {
441        rc = sPanCtrl->stopPan();
442    } else if (!strcmp(argv[1], "status")) {
443        char *tmp = NULL;
444
445        asprintf(&tmp, "Pan services %s",
446                 (sPanCtrl->isPanStarted() ? "started" : "stopped"));
447        cli->sendMsg(ResponseCode::PanStatusResult, tmp, false);
448        free(tmp);
449        return 0;
450    } else {
451        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown pan cmd", false);
452        return 0;
453    }
454
455    if (!rc) {
456        cli->sendMsg(ResponseCode::CommandOkay, "Pan operation succeeded", false);
457    } else {
458        cli->sendMsg(ResponseCode::OperationFailed, "Pan operation failed", true);
459    }
460
461    return 0;
462}
463