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 // #define LOG_NDEBUG 0 18 19 #include <stdlib.h> 20 #include <sys/socket.h> 21 #include <sys/types.h> 22 #include <netinet/in.h> 23 #include <arpa/inet.h> 24 #include <dirent.h> 25 #include <errno.h> 26 #include <string.h> 27 #include <fcntl.h> 28 #include <linux/if.h> 29 30 #define LOG_TAG "CommandListener" 31 32 #include <cutils/log.h> 33 #include <netutils/ifc.h> 34 #include <sysutils/SocketClient.h> 35 36 #include "CommandListener.h" 37 #include "ResponseCode.h" 38 #include "ThrottleController.h" 39 #include "BandwidthController.h" 40 #include "IdletimerController.h" 41 #include "SecondaryTableController.h" 42 #include "oem_iptables_hook.h" 43 44 45 TetherController *CommandListener::sTetherCtrl = NULL; 46 NatController *CommandListener::sNatCtrl = NULL; 47 PppController *CommandListener::sPppCtrl = NULL; 48 PanController *CommandListener::sPanCtrl = NULL; 49 SoftapController *CommandListener::sSoftapCtrl = NULL; 50 BandwidthController * CommandListener::sBandwidthCtrl = NULL; 51 IdletimerController * CommandListener::sIdletimerCtrl = NULL; 52 ResolverController *CommandListener::sResolverCtrl = NULL; 53 SecondaryTableController *CommandListener::sSecondaryTableCtrl = NULL; 54 55 CommandListener::CommandListener() : 56 FrameworkListener("netd", true) { 57 registerCmd(new InterfaceCmd()); 58 registerCmd(new IpFwdCmd()); 59 registerCmd(new TetherCmd()); 60 registerCmd(new NatCmd()); 61 registerCmd(new ListTtysCmd()); 62 registerCmd(new PppdCmd()); 63 registerCmd(new PanCmd()); 64 registerCmd(new SoftapCmd()); 65 registerCmd(new BandwidthControlCmd()); 66 registerCmd(new IdletimerControlCmd()); 67 registerCmd(new ResolverCmd()); 68 69 if (!sSecondaryTableCtrl) 70 sSecondaryTableCtrl = new SecondaryTableController(); 71 if (!sTetherCtrl) 72 sTetherCtrl = new TetherController(); 73 if (!sNatCtrl) 74 sNatCtrl = new NatController(sSecondaryTableCtrl); 75 if (!sPppCtrl) 76 sPppCtrl = new PppController(); 77 if (!sPanCtrl) 78 sPanCtrl = new PanController(); 79 if (!sSoftapCtrl) 80 sSoftapCtrl = new SoftapController(); 81 if (!sBandwidthCtrl) 82 sBandwidthCtrl = new BandwidthController(); 83 if (!sIdletimerCtrl) 84 sIdletimerCtrl = new IdletimerController(); 85 if (!sResolverCtrl) 86 sResolverCtrl = new ResolverController(); 87 88 /* 89 * This is the only time controllers are allowed to touch 90 * top-level chains in iptables. 91 * Each controller should setup custom chains and hook them into 92 * the top-level ones. 93 * THE ORDER IS IMPORTANT. TRIPPLE CHECK EACH setup function. 94 */ 95 /* Does DROP in nat: PREROUTING, FORWARD, OUTPUT */ 96 setupOemIptablesHook(); 97 /* Does DROPs in FORWARD by default */ 98 sNatCtrl->setupIptablesHooks(); 99 /* 100 * Does REJECT in INPUT, OUTPUT. Does counting also. 101 * No DROP/REJECT allowed later in netfilter-flow hook order. 102 */ 103 sBandwidthCtrl->setupIptablesHooks(); 104 /* 105 * Counts in nat: PREROUTING, POSTROUTING. 106 * No DROP/REJECT allowed later in netfilter-flow hook order. 107 */ 108 sIdletimerCtrl->setupIptablesHooks(); 109 110 sBandwidthCtrl->enableBandwidthControl(false); 111 } 112 113 CommandListener::InterfaceCmd::InterfaceCmd() : 114 NetdCommand("interface") { 115 } 116 117 int CommandListener::writeFile(const char *path, const char *value, int size) { 118 int fd = open(path, O_WRONLY); 119 if (fd < 0) { 120 ALOGE("Failed to open %s: %s", path, strerror(errno)); 121 return -1; 122 } 123 124 if (write(fd, value, size) != size) { 125 ALOGE("Failed to write %s: %s", path, strerror(errno)); 126 close(fd); 127 return -1; 128 } 129 close(fd); 130 return 0; 131 } 132 133 int CommandListener::InterfaceCmd::runCommand(SocketClient *cli, 134 int argc, char **argv) { 135 if (argc < 2) { 136 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); 137 return 0; 138 } 139 140 if (!strcmp(argv[1], "list")) { 141 DIR *d; 142 struct dirent *de; 143 144 if (!(d = opendir("/sys/class/net"))) { 145 cli->sendMsg(ResponseCode::OperationFailed, "Failed to open sysfs dir", true); 146 return 0; 147 } 148 149 while((de = readdir(d))) { 150 if (de->d_name[0] == '.') 151 continue; 152 cli->sendMsg(ResponseCode::InterfaceListResult, de->d_name, false); 153 } 154 closedir(d); 155 cli->sendMsg(ResponseCode::CommandOkay, "Interface list completed", false); 156 return 0; 157 } else if (!strcmp(argv[1], "readrxcounter")) { 158 if (argc != 3) { 159 cli->sendMsg(ResponseCode::CommandSyntaxError, 160 "Usage: interface readrxcounter <interface>", false); 161 return 0; 162 } 163 unsigned long rx = 0, tx = 0; 164 if (readInterfaceCounters(argv[2], &rx, &tx)) { 165 cli->sendMsg(ResponseCode::OperationFailed, "Failed to read counters", true); 166 return 0; 167 } 168 169 char *msg; 170 asprintf(&msg, "%lu", rx); 171 cli->sendMsg(ResponseCode::InterfaceRxCounterResult, msg, false); 172 free(msg); 173 174 return 0; 175 } else if (!strcmp(argv[1], "readtxcounter")) { 176 if (argc != 3) { 177 cli->sendMsg(ResponseCode::CommandSyntaxError, 178 "Usage: interface readtxcounter <interface>", false); 179 return 0; 180 } 181 unsigned long rx = 0, tx = 0; 182 if (readInterfaceCounters(argv[2], &rx, &tx)) { 183 cli->sendMsg(ResponseCode::OperationFailed, "Failed to read counters", true); 184 return 0; 185 } 186 187 char *msg = NULL; 188 asprintf(&msg, "%lu", tx); 189 cli->sendMsg(ResponseCode::InterfaceTxCounterResult, msg, false); 190 free(msg); 191 return 0; 192 } else if (!strcmp(argv[1], "getthrottle")) { 193 if (argc != 4 || (argc == 4 && (strcmp(argv[3], "rx") && (strcmp(argv[3], "tx"))))) { 194 cli->sendMsg(ResponseCode::CommandSyntaxError, 195 "Usage: interface getthrottle <interface> <rx|tx>", false); 196 return 0; 197 } 198 int val = 0; 199 int rc = 0; 200 int voldRc = ResponseCode::InterfaceRxThrottleResult; 201 202 if (!strcmp(argv[3], "rx")) { 203 rc = ThrottleController::getInterfaceRxThrottle(argv[2], &val); 204 } else { 205 rc = ThrottleController::getInterfaceTxThrottle(argv[2], &val); 206 voldRc = ResponseCode::InterfaceTxThrottleResult; 207 } 208 if (rc) { 209 cli->sendMsg(ResponseCode::OperationFailed, "Failed to get throttle", true); 210 } else { 211 char *msg = NULL; 212 asprintf(&msg, "%u", val); 213 cli->sendMsg(voldRc, msg, false); 214 free(msg); 215 return 0; 216 } 217 return 0; 218 } else if (!strcmp(argv[1], "setthrottle")) { 219 if (argc != 5) { 220 cli->sendMsg(ResponseCode::CommandSyntaxError, 221 "Usage: interface setthrottle <interface> <rx_kbps> <tx_kbps>", false); 222 return 0; 223 } 224 if (ThrottleController::setInterfaceThrottle(argv[2], atoi(argv[3]), atoi(argv[4]))) { 225 cli->sendMsg(ResponseCode::OperationFailed, "Failed to set throttle", true); 226 } else { 227 cli->sendMsg(ResponseCode::CommandOkay, "Interface throttling set", false); 228 } 229 return 0; 230 } else { 231 /* 232 * These commands take a minimum of 3 arguments 233 */ 234 if (argc < 3) { 235 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); 236 return 0; 237 } 238 239 // 0 1 2 3 4 5 6 7 240 // interface route add/remove iface default/secondary dest prefix gateway 241 if (!strcmp(argv[1], "route")) { 242 int prefix_length = 0; 243 if (argc < 8) { 244 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); 245 return 0; 246 } 247 if (sscanf(argv[6], "%d", &prefix_length) != 1) { 248 cli->sendMsg(ResponseCode::CommandParameterError, "Invalid route prefix", false); 249 return 0; 250 } 251 if (!strcmp(argv[2], "add")) { 252 if (!strcmp(argv[4], "default")) { 253 if (ifc_add_route(argv[3], argv[5], prefix_length, argv[7])) { 254 cli->sendMsg(ResponseCode::OperationFailed, 255 "Failed to add route to default table", true); 256 } else { 257 cli->sendMsg(ResponseCode::CommandOkay, 258 "Route added to default table", false); 259 } 260 } else if (!strcmp(argv[4], "secondary")) { 261 return sSecondaryTableCtrl->addRoute(cli, argv[3], argv[5], 262 prefix_length, argv[7]); 263 } else { 264 cli->sendMsg(ResponseCode::CommandParameterError, 265 "Invalid route type, expecting 'default' or 'secondary'", false); 266 return 0; 267 } 268 } else if (!strcmp(argv[2], "remove")) { 269 if (!strcmp(argv[4], "default")) { 270 if (ifc_remove_route(argv[3], argv[5], prefix_length, argv[7])) { 271 cli->sendMsg(ResponseCode::OperationFailed, 272 "Failed to remove route from default table", true); 273 } else { 274 cli->sendMsg(ResponseCode::CommandOkay, 275 "Route removed from default table", false); 276 } 277 } else if (!strcmp(argv[4], "secondary")) { 278 return sSecondaryTableCtrl->removeRoute(cli, argv[3], argv[5], 279 prefix_length, argv[7]); 280 } else { 281 cli->sendMsg(ResponseCode::CommandParameterError, 282 "Invalid route type, expecting 'default' or 'secondary'", false); 283 return 0; 284 } 285 } else { 286 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown interface cmd", false); 287 } 288 return 0; 289 } 290 291 if (!strcmp(argv[1], "getcfg")) { 292 struct in_addr addr; 293 int prefixLength; 294 unsigned char hwaddr[6]; 295 unsigned flags = 0; 296 297 ifc_init(); 298 memset(hwaddr, 0, sizeof(hwaddr)); 299 300 if (ifc_get_info(argv[2], &addr.s_addr, &prefixLength, &flags)) { 301 cli->sendMsg(ResponseCode::OperationFailed, "Interface not found", true); 302 ifc_close(); 303 return 0; 304 } 305 306 if (ifc_get_hwaddr(argv[2], (void *) hwaddr)) { 307 ALOGW("Failed to retrieve HW addr for %s (%s)", argv[2], strerror(errno)); 308 } 309 310 char *addr_s = strdup(inet_ntoa(addr)); 311 const char *updown, *brdcst, *loopbk, *ppp, *running, *multi; 312 313 updown = (flags & IFF_UP) ? "up" : "down"; 314 brdcst = (flags & IFF_BROADCAST) ? " broadcast" : ""; 315 loopbk = (flags & IFF_LOOPBACK) ? " loopback" : ""; 316 ppp = (flags & IFF_POINTOPOINT) ? " point-to-point" : ""; 317 running = (flags & IFF_RUNNING) ? " running" : ""; 318 multi = (flags & IFF_MULTICAST) ? " multicast" : ""; 319 320 char *flag_s; 321 322 asprintf(&flag_s, "%s%s%s%s%s%s", updown, brdcst, loopbk, ppp, running, multi); 323 324 char *msg = NULL; 325 asprintf(&msg, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x %s %d %s", 326 hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5], 327 addr_s, prefixLength, flag_s); 328 329 cli->sendMsg(ResponseCode::InterfaceGetCfgResult, msg, false); 330 331 free(addr_s); 332 free(flag_s); 333 free(msg); 334 335 ifc_close(); 336 return 0; 337 } else if (!strcmp(argv[1], "setcfg")) { 338 // arglist: iface addr prefixLength flags 339 if (argc < 5) { 340 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); 341 return 0; 342 } 343 ALOGD("Setting iface cfg"); 344 345 struct in_addr addr; 346 unsigned flags = 0; 347 348 if (!inet_aton(argv[3], &addr)) { 349 cli->sendMsg(ResponseCode::CommandParameterError, "Invalid address", false); 350 return 0; 351 } 352 353 ifc_init(); 354 if (ifc_set_addr(argv[2], addr.s_addr)) { 355 cli->sendMsg(ResponseCode::OperationFailed, "Failed to set address", true); 356 ifc_close(); 357 return 0; 358 } 359 360 //Set prefix length on a non zero address 361 if (addr.s_addr != 0 && ifc_set_prefixLength(argv[2], atoi(argv[4]))) { 362 cli->sendMsg(ResponseCode::OperationFailed, "Failed to set prefixLength", true); 363 ifc_close(); 364 return 0; 365 } 366 367 /* Process flags */ 368 for (int i = 5; i < argc; i++) { 369 char *flag = argv[i]; 370 if (!strcmp(flag, "up")) { 371 ALOGD("Trying to bring up %s", argv[2]); 372 if (ifc_up(argv[2])) { 373 ALOGE("Error upping interface"); 374 cli->sendMsg(ResponseCode::OperationFailed, "Failed to up interface", true); 375 ifc_close(); 376 return 0; 377 } 378 } else if (!strcmp(flag, "down")) { 379 ALOGD("Trying to bring down %s", argv[2]); 380 if (ifc_down(argv[2])) { 381 ALOGE("Error downing interface"); 382 cli->sendMsg(ResponseCode::OperationFailed, "Failed to down interface", true); 383 ifc_close(); 384 return 0; 385 } 386 } else if (!strcmp(flag, "broadcast")) { 387 // currently ignored 388 } else if (!strcmp(flag, "multicast")) { 389 // currently ignored 390 } else if (!strcmp(flag, "running")) { 391 // currently ignored 392 } else if (!strcmp(flag, "loopback")) { 393 // currently ignored 394 } else if (!strcmp(flag, "point-to-point")) { 395 // currently ignored 396 } else { 397 cli->sendMsg(ResponseCode::CommandParameterError, "Flag unsupported", false); 398 ifc_close(); 399 return 0; 400 } 401 } 402 403 cli->sendMsg(ResponseCode::CommandOkay, "Interface configuration set", false); 404 ifc_close(); 405 return 0; 406 } else if (!strcmp(argv[1], "clearaddrs")) { 407 // arglist: iface 408 ALOGD("Clearing all IP addresses on %s", argv[2]); 409 410 ifc_clear_addresses(argv[2]); 411 412 cli->sendMsg(ResponseCode::CommandOkay, "Interface IP addresses cleared", false); 413 return 0; 414 } else if (!strcmp(argv[1], "ipv6privacyextensions")) { 415 if (argc != 4) { 416 cli->sendMsg(ResponseCode::CommandSyntaxError, 417 "Usage: interface ipv6privacyextensions <interface> <enable|disable>", 418 false); 419 return 0; 420 } 421 422 char *tmp; 423 asprintf(&tmp, "/proc/sys/net/ipv6/conf/%s/use_tempaddr", argv[2]); 424 425 if (writeFile(tmp, !strncmp(argv[3], "enable", 7) ? "2" : "0", 1) < 0) { 426 free(tmp); 427 cli->sendMsg(ResponseCode::OperationFailed, 428 "Failed to set ipv6 privacy extensions", true); 429 return 0; 430 } 431 432 free(tmp); 433 cli->sendMsg(ResponseCode::CommandOkay, "IPv6 privacy extensions changed", false); 434 return 0; 435 } else if (!strcmp(argv[1], "ipv6")) { 436 if (argc != 4) { 437 cli->sendMsg(ResponseCode::CommandSyntaxError, 438 "Usage: interface ipv6 <interface> <enable|disable>", 439 false); 440 return 0; 441 } 442 443 char *tmp; 444 asprintf(&tmp, "/proc/sys/net/ipv6/conf/%s/disable_ipv6", argv[2]); 445 446 if (writeFile(tmp, !strncmp(argv[3], "enable", 7) ? "0" : "1", 1) < 0) { 447 free(tmp); 448 cli->sendMsg(ResponseCode::OperationFailed, 449 "Failed to change IPv6 state", true); 450 return 0; 451 } 452 453 free(tmp); 454 cli->sendMsg(ResponseCode::CommandOkay, "IPv6 state changed", false); 455 return 0; 456 } else { 457 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown interface cmd", false); 458 return 0; 459 } 460 } 461 return 0; 462 } 463 464 465 CommandListener::ListTtysCmd::ListTtysCmd() : 466 NetdCommand("list_ttys") { 467 } 468 469 int CommandListener::ListTtysCmd::runCommand(SocketClient *cli, 470 int argc, char **argv) { 471 TtyCollection *tlist = sPppCtrl->getTtyList(); 472 TtyCollection::iterator it; 473 474 for (it = tlist->begin(); it != tlist->end(); ++it) { 475 cli->sendMsg(ResponseCode::TtyListResult, *it, false); 476 } 477 478 cli->sendMsg(ResponseCode::CommandOkay, "Ttys listed.", false); 479 return 0; 480 } 481 482 CommandListener::IpFwdCmd::IpFwdCmd() : 483 NetdCommand("ipfwd") { 484 } 485 486 int CommandListener::IpFwdCmd::runCommand(SocketClient *cli, 487 int argc, char **argv) { 488 int rc = 0; 489 490 if (argc < 2) { 491 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); 492 return 0; 493 } 494 495 if (!strcmp(argv[1], "status")) { 496 char *tmp = NULL; 497 498 asprintf(&tmp, "Forwarding %s", (sTetherCtrl->getIpFwdEnabled() ? "enabled" : "disabled")); 499 cli->sendMsg(ResponseCode::IpFwdStatusResult, tmp, false); 500 free(tmp); 501 return 0; 502 } else if (!strcmp(argv[1], "enable")) { 503 rc = sTetherCtrl->setIpFwdEnabled(true); 504 } else if (!strcmp(argv[1], "disable")) { 505 rc = sTetherCtrl->setIpFwdEnabled(false); 506 } else { 507 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown ipfwd cmd", false); 508 return 0; 509 } 510 511 if (!rc) { 512 cli->sendMsg(ResponseCode::CommandOkay, "ipfwd operation succeeded", false); 513 } else { 514 cli->sendMsg(ResponseCode::OperationFailed, "ipfwd operation failed", true); 515 } 516 517 return 0; 518 } 519 520 CommandListener::TetherCmd::TetherCmd() : 521 NetdCommand("tether") { 522 } 523 524 int CommandListener::TetherCmd::runCommand(SocketClient *cli, 525 int argc, char **argv) { 526 int rc = 0; 527 528 if (argc < 2) { 529 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); 530 return 0; 531 } 532 533 if (!strcmp(argv[1], "stop")) { 534 rc = sTetherCtrl->stopTethering(); 535 } else if (!strcmp(argv[1], "status")) { 536 char *tmp = NULL; 537 538 asprintf(&tmp, "Tethering services %s", 539 (sTetherCtrl->isTetheringStarted() ? "started" : "stopped")); 540 cli->sendMsg(ResponseCode::TetherStatusResult, tmp, false); 541 free(tmp); 542 return 0; 543 } else { 544 /* 545 * These commands take a minimum of 4 arguments 546 */ 547 if (argc < 4) { 548 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); 549 return 0; 550 } 551 552 if (!strcmp(argv[1], "start")) { 553 if (argc % 2 == 1) { 554 cli->sendMsg(ResponseCode::CommandSyntaxError, "Bad number of arguments", false); 555 return 0; 556 } 557 558 int num_addrs = argc - 2; 559 int arg_index = 2; 560 int array_index = 0; 561 in_addr *addrs = (in_addr *)malloc(sizeof(in_addr) * num_addrs); 562 while (array_index < num_addrs) { 563 if (!inet_aton(argv[arg_index++], &(addrs[array_index++]))) { 564 cli->sendMsg(ResponseCode::CommandParameterError, "Invalid address", false); 565 free(addrs); 566 return 0; 567 } 568 } 569 rc = sTetherCtrl->startTethering(num_addrs, addrs); 570 free(addrs); 571 } else if (!strcmp(argv[1], "interface")) { 572 if (!strcmp(argv[2], "add")) { 573 rc = sTetherCtrl->tetherInterface(argv[3]); 574 } else if (!strcmp(argv[2], "remove")) { 575 rc = sTetherCtrl->untetherInterface(argv[3]); 576 } else if (!strcmp(argv[2], "list")) { 577 InterfaceCollection *ilist = sTetherCtrl->getTetheredInterfaceList(); 578 InterfaceCollection::iterator it; 579 580 for (it = ilist->begin(); it != ilist->end(); ++it) { 581 cli->sendMsg(ResponseCode::TetherInterfaceListResult, *it, false); 582 } 583 } else { 584 cli->sendMsg(ResponseCode::CommandParameterError, 585 "Unknown tether interface operation", false); 586 return 0; 587 } 588 } else if (!strcmp(argv[1], "dns")) { 589 if (!strcmp(argv[2], "set")) { 590 rc = sTetherCtrl->setDnsForwarders(&argv[3], argc - 3); 591 } else if (!strcmp(argv[2], "list")) { 592 NetAddressCollection *dlist = sTetherCtrl->getDnsForwarders(); 593 NetAddressCollection::iterator it; 594 595 for (it = dlist->begin(); it != dlist->end(); ++it) { 596 cli->sendMsg(ResponseCode::TetherDnsFwdTgtListResult, inet_ntoa(*it), false); 597 } 598 } else { 599 cli->sendMsg(ResponseCode::CommandParameterError, 600 "Unknown tether interface operation", false); 601 return 0; 602 } 603 } else { 604 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown tether cmd", false); 605 return 0; 606 } 607 } 608 609 if (!rc) { 610 cli->sendMsg(ResponseCode::CommandOkay, "Tether operation succeeded", false); 611 } else { 612 cli->sendMsg(ResponseCode::OperationFailed, "Tether operation failed", true); 613 } 614 615 return 0; 616 } 617 618 CommandListener::NatCmd::NatCmd() : 619 NetdCommand("nat") { 620 } 621 622 int CommandListener::NatCmd::runCommand(SocketClient *cli, 623 int argc, char **argv) { 624 int rc = 0; 625 626 if (argc < 5) { 627 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); 628 return 0; 629 } 630 631 if (!strcmp(argv[1], "enable")) { 632 rc = sNatCtrl->enableNat(argc, argv); 633 if(!rc) { 634 /* Ignore ifaces for now. */ 635 rc = sBandwidthCtrl->setGlobalAlertInForwardChain(); 636 } 637 } else if (!strcmp(argv[1], "disable")) { 638 /* Ignore ifaces for now. */ 639 rc = sBandwidthCtrl->removeGlobalAlertInForwardChain(); 640 rc |= sNatCtrl->disableNat(argc, argv); 641 } else { 642 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown nat cmd", false); 643 return 0; 644 } 645 646 if (!rc) { 647 cli->sendMsg(ResponseCode::CommandOkay, "Nat operation succeeded", false); 648 } else { 649 cli->sendMsg(ResponseCode::OperationFailed, "Nat operation failed", true); 650 } 651 652 return 0; 653 } 654 655 CommandListener::PppdCmd::PppdCmd() : 656 NetdCommand("pppd") { 657 } 658 659 int CommandListener::PppdCmd::runCommand(SocketClient *cli, 660 int argc, char **argv) { 661 int rc = 0; 662 663 if (argc < 3) { 664 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); 665 return 0; 666 } 667 668 if (!strcmp(argv[1], "attach")) { 669 struct in_addr l, r, dns1, dns2; 670 671 memset(&dns1, sizeof(struct in_addr), 0); 672 memset(&dns2, sizeof(struct in_addr), 0); 673 674 if (!inet_aton(argv[3], &l)) { 675 cli->sendMsg(ResponseCode::CommandParameterError, "Invalid local address", false); 676 return 0; 677 } 678 if (!inet_aton(argv[4], &r)) { 679 cli->sendMsg(ResponseCode::CommandParameterError, "Invalid remote address", false); 680 return 0; 681 } 682 if ((argc > 3) && (!inet_aton(argv[5], &dns1))) { 683 cli->sendMsg(ResponseCode::CommandParameterError, "Invalid dns1 address", false); 684 return 0; 685 } 686 if ((argc > 4) && (!inet_aton(argv[6], &dns2))) { 687 cli->sendMsg(ResponseCode::CommandParameterError, "Invalid dns2 address", false); 688 return 0; 689 } 690 rc = sPppCtrl->attachPppd(argv[2], l, r, dns1, dns2); 691 } else if (!strcmp(argv[1], "detach")) { 692 rc = sPppCtrl->detachPppd(argv[2]); 693 } else { 694 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown pppd cmd", false); 695 return 0; 696 } 697 698 if (!rc) { 699 cli->sendMsg(ResponseCode::CommandOkay, "Pppd operation succeeded", false); 700 } else { 701 cli->sendMsg(ResponseCode::OperationFailed, "Pppd operation failed", true); 702 } 703 704 return 0; 705 } 706 707 CommandListener::PanCmd::PanCmd() : 708 NetdCommand("pan") { 709 } 710 711 int CommandListener::PanCmd::runCommand(SocketClient *cli, 712 int argc, char **argv) { 713 int rc = 0; 714 715 if (argc < 2) { 716 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); 717 return 0; 718 } 719 720 if (!strcmp(argv[1], "start")) { 721 rc = sPanCtrl->startPan(); 722 } else if (!strcmp(argv[1], "stop")) { 723 rc = sPanCtrl->stopPan(); 724 } else if (!strcmp(argv[1], "status")) { 725 char *tmp = NULL; 726 727 asprintf(&tmp, "Pan services %s", 728 (sPanCtrl->isPanStarted() ? "started" : "stopped")); 729 cli->sendMsg(ResponseCode::PanStatusResult, tmp, false); 730 free(tmp); 731 return 0; 732 } else { 733 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown pan cmd", false); 734 return 0; 735 } 736 737 if (!rc) { 738 cli->sendMsg(ResponseCode::CommandOkay, "Pan operation succeeded", false); 739 } else { 740 cli->sendMsg(ResponseCode::OperationFailed, "Pan operation failed", true); 741 } 742 743 return 0; 744 } 745 746 CommandListener::SoftapCmd::SoftapCmd() : 747 NetdCommand("softap") { 748 } 749 750 int CommandListener::SoftapCmd::runCommand(SocketClient *cli, 751 int argc, char **argv) { 752 int rc = 0, flag = 0; 753 char *retbuf = NULL; 754 755 if (argc < 2) { 756 cli->sendMsg(ResponseCode::CommandSyntaxError, "Softap Missing argument", false); 757 return 0; 758 } 759 760 if (!strcmp(argv[1], "start")) { 761 rc = sSoftapCtrl->startDriver(argv[2]); 762 } else if (!strcmp(argv[1], "stop")) { 763 rc = sSoftapCtrl->stopDriver(argv[2]); 764 } else if (!strcmp(argv[1], "startap")) { 765 rc = sSoftapCtrl->startSoftap(); 766 } else if (!strcmp(argv[1], "stopap")) { 767 rc = sSoftapCtrl->stopSoftap(); 768 } else if (!strcmp(argv[1], "fwreload")) { 769 rc = sSoftapCtrl->fwReloadSoftap(argc, argv); 770 } else if (!strcmp(argv[1], "clients")) { 771 rc = sSoftapCtrl->clientsSoftap(&retbuf); 772 if (!rc) { 773 cli->sendMsg(ResponseCode::CommandOkay, retbuf, false); 774 free(retbuf); 775 return 0; 776 } 777 } else if (!strcmp(argv[1], "status")) { 778 asprintf(&retbuf, "Softap service %s", 779 (sSoftapCtrl->isSoftapStarted() ? "started" : "stopped")); 780 cli->sendMsg(ResponseCode::SoftapStatusResult, retbuf, false); 781 free(retbuf); 782 return 0; 783 } else if (!strcmp(argv[1], "set")) { 784 rc = sSoftapCtrl->setSoftap(argc, argv); 785 } else { 786 cli->sendMsg(ResponseCode::CommandSyntaxError, "Softap Unknown cmd", false); 787 return 0; 788 } 789 790 if (!rc) { 791 cli->sendMsg(ResponseCode::CommandOkay, "Softap operation succeeded", false); 792 } else { 793 cli->sendMsg(ResponseCode::OperationFailed, "Softap operation failed", true); 794 } 795 796 return 0; 797 } 798 799 CommandListener::ResolverCmd::ResolverCmd() : 800 NetdCommand("resolver") { 801 } 802 803 int CommandListener::ResolverCmd::runCommand(SocketClient *cli, int argc, char **argv) { 804 int rc = 0; 805 struct in_addr addr; 806 807 if (argc < 2) { 808 cli->sendMsg(ResponseCode::CommandSyntaxError, "Resolver missing arguments", false); 809 return 0; 810 } 811 812 if (!strcmp(argv[1], "setdefaultif")) { // "resolver setdefaultif <iface>" 813 if (argc == 3) { 814 rc = sResolverCtrl->setDefaultInterface(argv[2]); 815 } else { 816 cli->sendMsg(ResponseCode::CommandSyntaxError, 817 "Wrong number of arguments to resolver setdefaultif", false); 818 return 0; 819 } 820 } else if (!strcmp(argv[1], "setifdns")) { // "resolver setifdns <iface> <dns1> <dns2> ..." 821 if (argc >= 4) { 822 rc = sResolverCtrl->setInterfaceDnsServers(argv[2], &argv[3], argc - 3); 823 } else { 824 cli->sendMsg(ResponseCode::CommandSyntaxError, 825 "Wrong number of arguments to resolver setifdns", false); 826 return 0; 827 } 828 829 // set the address of the interface to which the name servers 830 // are bound. Required in order to bind to right interface when 831 // doing the dns query. 832 if (!rc) { 833 ifc_init(); 834 ifc_get_info(argv[2], &addr.s_addr, NULL, 0); 835 836 rc = sResolverCtrl->setInterfaceAddress(argv[2], &addr); 837 } 838 } else if (!strcmp(argv[1], "flushdefaultif")) { // "resolver flushdefaultif" 839 if (argc == 2) { 840 rc = sResolverCtrl->flushDefaultDnsCache(); 841 } else { 842 cli->sendMsg(ResponseCode::CommandSyntaxError, 843 "Wrong number of arguments to resolver flushdefaultif", false); 844 return 0; 845 } 846 } else if (!strcmp(argv[1], "flushif")) { // "resolver flushif <iface>" 847 if (argc == 3) { 848 rc = sResolverCtrl->flushInterfaceDnsCache(argv[2]); 849 } else { 850 cli->sendMsg(ResponseCode::CommandSyntaxError, 851 "Wrong number of arguments to resolver setdefaultif", false); 852 return 0; 853 } 854 } else { 855 cli->sendMsg(ResponseCode::CommandSyntaxError,"Resolver unknown command", false); 856 return 0; 857 } 858 859 if (!rc) { 860 cli->sendMsg(ResponseCode::CommandOkay, "Resolver command succeeded", false); 861 } else { 862 cli->sendMsg(ResponseCode::OperationFailed, "Resolver command failed", true); 863 } 864 865 return 0; 866 } 867 868 int CommandListener::readInterfaceCounters(const char *iface, unsigned long *rx, unsigned long *tx) { 869 FILE *fp = fopen("/proc/net/dev", "r"); 870 if (!fp) { 871 ALOGE("Failed to open /proc/net/dev (%s)", strerror(errno)); 872 return -1; 873 } 874 875 char buffer[512]; 876 877 fgets(buffer, sizeof(buffer), fp); // Header 1 878 fgets(buffer, sizeof(buffer), fp); // Header 2 879 while(fgets(buffer, sizeof(buffer), fp)) { 880 buffer[strlen(buffer)-1] = '\0'; 881 882 char name[31]; 883 unsigned long d; 884 sscanf(buffer, "%30s %lu %lu %lu %lu %lu %lu %lu %lu %lu", 885 name, rx, &d, &d, &d, &d, &d, &d, &d, tx); 886 char *rxString = strchr(name, ':'); 887 *rxString = '\0'; 888 rxString++; 889 // when the rx count gets too big it changes from "name: 999" to "name:1000" 890 // and the sscanf munge the two together. Detect that and fix 891 // note that all the %lu will be off by one and the real tx value will be in d 892 if (*rxString != '\0') { 893 *tx = d; 894 sscanf(rxString, "%20lu", rx); 895 } 896 if (strcmp(name, iface)) { 897 continue; 898 } 899 fclose(fp); 900 return 0; 901 } 902 903 fclose(fp); 904 *rx = 0; 905 *tx = 0; 906 return 0; 907 } 908 909 CommandListener::BandwidthControlCmd::BandwidthControlCmd() : 910 NetdCommand("bandwidth") { 911 } 912 913 void CommandListener::BandwidthControlCmd::sendGenericSyntaxError(SocketClient *cli, const char *usageMsg) { 914 char *msg; 915 asprintf(&msg, "Usage: bandwidth %s", usageMsg); 916 cli->sendMsg(ResponseCode::CommandSyntaxError, msg, false); 917 free(msg); 918 } 919 920 void CommandListener::BandwidthControlCmd::sendGenericOkFail(SocketClient *cli, int cond) { 921 if (!cond) { 922 cli->sendMsg(ResponseCode::CommandOkay, "Bandwidth command succeeeded", false); 923 } else { 924 cli->sendMsg(ResponseCode::OperationFailed, "Bandwidth command failed", false); 925 } 926 } 927 928 void CommandListener::BandwidthControlCmd::sendGenericOpFailed(SocketClient *cli, const char *errMsg) { 929 cli->sendMsg(ResponseCode::OperationFailed, errMsg, false); 930 } 931 932 int CommandListener::BandwidthControlCmd::runCommand(SocketClient *cli, int argc, char **argv) { 933 if (argc < 2) { 934 sendGenericSyntaxError(cli, "<cmds> <args...>"); 935 return 0; 936 } 937 938 ALOGV("bwctrlcmd: argc=%d %s %s ...", argc, argv[0], argv[1]); 939 940 if (!strcmp(argv[1], "enable")) { 941 int rc = sBandwidthCtrl->enableBandwidthControl(true); 942 sendGenericOkFail(cli, rc); 943 return 0; 944 945 } 946 if (!strcmp(argv[1], "disable")) { 947 int rc = sBandwidthCtrl->disableBandwidthControl(); 948 sendGenericOkFail(cli, rc); 949 return 0; 950 951 } 952 if (!strcmp(argv[1], "removequota") || !strcmp(argv[1], "rq")) { 953 if (argc != 3) { 954 sendGenericSyntaxError(cli, "removequota <interface>"); 955 return 0; 956 } 957 int rc = sBandwidthCtrl->removeInterfaceSharedQuota(argv[2]); 958 sendGenericOkFail(cli, rc); 959 return 0; 960 961 } 962 if (!strcmp(argv[1], "getquota") || !strcmp(argv[1], "gq")) { 963 int64_t bytes; 964 if (argc != 2) { 965 sendGenericSyntaxError(cli, "getquota"); 966 return 0; 967 } 968 int rc = sBandwidthCtrl->getInterfaceSharedQuota(&bytes); 969 if (rc) { 970 sendGenericOpFailed(cli, "Failed to get quota"); 971 return 0; 972 } 973 974 char *msg; 975 asprintf(&msg, "%lld", bytes); 976 cli->sendMsg(ResponseCode::QuotaCounterResult, msg, false); 977 free(msg); 978 return 0; 979 980 } 981 if (!strcmp(argv[1], "getiquota") || !strcmp(argv[1], "giq")) { 982 int64_t bytes; 983 if (argc != 3) { 984 sendGenericSyntaxError(cli, "getiquota <iface>"); 985 return 0; 986 } 987 988 int rc = sBandwidthCtrl->getInterfaceQuota(argv[2], &bytes); 989 if (rc) { 990 sendGenericOpFailed(cli, "Failed to get quota"); 991 return 0; 992 } 993 char *msg; 994 asprintf(&msg, "%lld", bytes); 995 cli->sendMsg(ResponseCode::QuotaCounterResult, msg, false); 996 free(msg); 997 return 0; 998 999 } 1000 if (!strcmp(argv[1], "setquota") || !strcmp(argv[1], "sq")) { 1001 if (argc != 4) { 1002 sendGenericSyntaxError(cli, "setquota <interface> <bytes>"); 1003 return 0; 1004 } 1005 int rc = sBandwidthCtrl->setInterfaceSharedQuota(argv[2], atoll(argv[3])); 1006 sendGenericOkFail(cli, rc); 1007 return 0; 1008 } 1009 if (!strcmp(argv[1], "setquotas") || !strcmp(argv[1], "sqs")) { 1010 int rc; 1011 if (argc < 4) { 1012 sendGenericSyntaxError(cli, "setquotas <bytes> <interface> ..."); 1013 return 0; 1014 } 1015 1016 for (int q = 3; argc >= 4; q++, argc--) { 1017 rc = sBandwidthCtrl->setInterfaceSharedQuota(argv[q], atoll(argv[2])); 1018 if (rc) { 1019 char *msg; 1020 asprintf(&msg, "bandwidth setquotas %s %s failed", argv[2], argv[q]); 1021 cli->sendMsg(ResponseCode::OperationFailed, 1022 msg, false); 1023 free(msg); 1024 return 0; 1025 } 1026 } 1027 sendGenericOkFail(cli, rc); 1028 return 0; 1029 1030 } 1031 if (!strcmp(argv[1], "removequotas") || !strcmp(argv[1], "rqs")) { 1032 int rc; 1033 if (argc < 3) { 1034 sendGenericSyntaxError(cli, "removequotas <interface> ..."); 1035 return 0; 1036 } 1037 1038 for (int q = 2; argc >= 3; q++, argc--) { 1039 rc = sBandwidthCtrl->removeInterfaceSharedQuota(argv[q]); 1040 if (rc) { 1041 char *msg; 1042 asprintf(&msg, "bandwidth removequotas %s failed", argv[q]); 1043 cli->sendMsg(ResponseCode::OperationFailed, 1044 msg, false); 1045 free(msg); 1046 return 0; 1047 } 1048 } 1049 sendGenericOkFail(cli, rc); 1050 return 0; 1051 1052 } 1053 if (!strcmp(argv[1], "removeiquota") || !strcmp(argv[1], "riq")) { 1054 if (argc != 3) { 1055 sendGenericSyntaxError(cli, "removeiquota <interface>"); 1056 return 0; 1057 } 1058 int rc = sBandwidthCtrl->removeInterfaceQuota(argv[2]); 1059 sendGenericOkFail(cli, rc); 1060 return 0; 1061 1062 } 1063 if (!strcmp(argv[1], "setiquota") || !strcmp(argv[1], "siq")) { 1064 if (argc != 4) { 1065 sendGenericSyntaxError(cli, "setiquota <interface> <bytes>"); 1066 return 0; 1067 } 1068 int rc = sBandwidthCtrl->setInterfaceQuota(argv[2], atoll(argv[3])); 1069 sendGenericOkFail(cli, rc); 1070 return 0; 1071 1072 } 1073 if (!strcmp(argv[1], "addnaughtyapps") || !strcmp(argv[1], "ana")) { 1074 if (argc < 3) { 1075 sendGenericSyntaxError(cli, "addnaughtyapps <appUid> ..."); 1076 return 0; 1077 } 1078 int rc = sBandwidthCtrl->addNaughtyApps(argc - 2, argv + 2); 1079 sendGenericOkFail(cli, rc); 1080 return 0; 1081 1082 1083 } 1084 if (!strcmp(argv[1], "removenaughtyapps") || !strcmp(argv[1], "rna")) { 1085 if (argc < 3) { 1086 sendGenericSyntaxError(cli, "removenaughtyapps <appUid> ..."); 1087 return 0; 1088 } 1089 int rc = sBandwidthCtrl->removeNaughtyApps(argc - 2, argv + 2); 1090 sendGenericOkFail(cli, rc); 1091 return 0; 1092 1093 } 1094 if (!strcmp(argv[1], "setglobalalert") || !strcmp(argv[1], "sga")) { 1095 if (argc != 3) { 1096 sendGenericSyntaxError(cli, "setglobalalert <bytes>"); 1097 return 0; 1098 } 1099 int rc = sBandwidthCtrl->setGlobalAlert(atoll(argv[2])); 1100 sendGenericOkFail(cli, rc); 1101 return 0; 1102 1103 } 1104 if (!strcmp(argv[1], "debugsettetherglobalalert") || !strcmp(argv[1], "dstga")) { 1105 if (argc != 4) { 1106 sendGenericSyntaxError(cli, "debugsettetherglobalalert <interface0> <interface1>"); 1107 return 0; 1108 } 1109 /* We ignore the interfaces for now. */ 1110 int rc = sBandwidthCtrl->setGlobalAlertInForwardChain(); 1111 sendGenericOkFail(cli, rc); 1112 return 0; 1113 1114 } 1115 if (!strcmp(argv[1], "removeglobalalert") || !strcmp(argv[1], "rga")) { 1116 if (argc != 2) { 1117 sendGenericSyntaxError(cli, "removeglobalalert"); 1118 return 0; 1119 } 1120 int rc = sBandwidthCtrl->removeGlobalAlert(); 1121 sendGenericOkFail(cli, rc); 1122 return 0; 1123 1124 } 1125 if (!strcmp(argv[1], "debugremovetetherglobalalert") || !strcmp(argv[1], "drtga")) { 1126 if (argc != 4) { 1127 sendGenericSyntaxError(cli, "debugremovetetherglobalalert <interface0> <interface1>"); 1128 return 0; 1129 } 1130 /* We ignore the interfaces for now. */ 1131 int rc = sBandwidthCtrl->removeGlobalAlertInForwardChain(); 1132 sendGenericOkFail(cli, rc); 1133 return 0; 1134 1135 } 1136 if (!strcmp(argv[1], "setsharedalert") || !strcmp(argv[1], "ssa")) { 1137 if (argc != 3) { 1138 sendGenericSyntaxError(cli, "setsharedalert <bytes>"); 1139 return 0; 1140 } 1141 int rc = sBandwidthCtrl->setSharedAlert(atoll(argv[2])); 1142 sendGenericOkFail(cli, rc); 1143 return 0; 1144 1145 } 1146 if (!strcmp(argv[1], "removesharedalert") || !strcmp(argv[1], "rsa")) { 1147 if (argc != 2) { 1148 sendGenericSyntaxError(cli, "removesharedalert"); 1149 return 0; 1150 } 1151 int rc = sBandwidthCtrl->removeSharedAlert(); 1152 sendGenericOkFail(cli, rc); 1153 return 0; 1154 1155 } 1156 if (!strcmp(argv[1], "setinterfacealert") || !strcmp(argv[1], "sia")) { 1157 if (argc != 4) { 1158 sendGenericSyntaxError(cli, "setinterfacealert <interface> <bytes>"); 1159 return 0; 1160 } 1161 int rc = sBandwidthCtrl->setInterfaceAlert(argv[2], atoll(argv[3])); 1162 sendGenericOkFail(cli, rc); 1163 return 0; 1164 1165 } 1166 if (!strcmp(argv[1], "removeinterfacealert") || !strcmp(argv[1], "ria")) { 1167 if (argc != 3) { 1168 sendGenericSyntaxError(cli, "removeinterfacealert <interface>"); 1169 return 0; 1170 } 1171 int rc = sBandwidthCtrl->removeInterfaceAlert(argv[2]); 1172 sendGenericOkFail(cli, rc); 1173 return 0; 1174 1175 } 1176 if (!strcmp(argv[1], "gettetherstats") || !strcmp(argv[1], "gts")) { 1177 BandwidthController::TetherStats tetherStats; 1178 std::string extraProcessingInfo = ""; 1179 if (argc != 4) { 1180 sendGenericSyntaxError(cli, "gettetherstats <interface0> <interface1>"); 1181 return 0; 1182 } 1183 1184 tetherStats.ifaceIn = argv[2]; 1185 tetherStats.ifaceOut = argv[3]; 1186 int rc = sBandwidthCtrl->getTetherStats(tetherStats, extraProcessingInfo); 1187 if (rc) { 1188 extraProcessingInfo.insert(0, "Failed to get tethering stats.\n"); 1189 sendGenericOpFailed(cli, extraProcessingInfo.c_str()); 1190 return 0; 1191 } 1192 1193 char *msg = tetherStats.getStatsLine(); 1194 cli->sendMsg(ResponseCode::TetheringStatsResult, msg, false); 1195 free(msg); 1196 return 0; 1197 1198 } 1199 1200 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown bandwidth cmd", false); 1201 return 0; 1202 } 1203 1204 CommandListener::IdletimerControlCmd::IdletimerControlCmd() : 1205 NetdCommand("idletimer") { 1206 } 1207 1208 int CommandListener::IdletimerControlCmd::runCommand(SocketClient *cli, int argc, char **argv) { 1209 // TODO(ashish): Change the error statements 1210 if (argc < 2) { 1211 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); 1212 return 0; 1213 } 1214 1215 ALOGV("idletimerctrlcmd: argc=%d %s %s ...", argc, argv[0], argv[1]); 1216 1217 if (!strcmp(argv[1], "enable")) { 1218 if (0 != sIdletimerCtrl->enableIdletimerControl()) { 1219 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); 1220 } else { 1221 cli->sendMsg(ResponseCode::CommandOkay, "Enable success", false); 1222 } 1223 return 0; 1224 1225 } 1226 if (!strcmp(argv[1], "disable")) { 1227 if (0 != sIdletimerCtrl->disableIdletimerControl()) { 1228 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); 1229 } else { 1230 cli->sendMsg(ResponseCode::CommandOkay, "Disable success", false); 1231 } 1232 return 0; 1233 } 1234 if (!strcmp(argv[1], "add")) { 1235 if (argc != 4) { 1236 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); 1237 return 0; 1238 } 1239 if(0 != sIdletimerCtrl->addInterfaceIdletimer(argv[2], atoi(argv[3]))) { 1240 cli->sendMsg(ResponseCode::OperationFailed, "Failed to add interface", false); 1241 } else { 1242 cli->sendMsg(ResponseCode::CommandOkay, "Add success", false); 1243 } 1244 return 0; 1245 } 1246 if (!strcmp(argv[1], "remove")) { 1247 if (argc != 4) { 1248 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); 1249 return 0; 1250 } 1251 // ashish: fixme timeout 1252 if (0 != sIdletimerCtrl->removeInterfaceIdletimer(argv[2], atoi(argv[3]))) { 1253 cli->sendMsg(ResponseCode::OperationFailed, "Failed to remove interface", false); 1254 } else { 1255 cli->sendMsg(ResponseCode::CommandOkay, "Remove success", false); 1256 } 1257 return 0; 1258 } 1259 1260 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown idletimer cmd", false); 1261 return 0; 1262 } 1263