CommandListener.cpp revision 90f374a7f4b111eeb1ed19feb52350c8f32c169d
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 45TetherController *CommandListener::sTetherCtrl = NULL; 46NatController *CommandListener::sNatCtrl = NULL; 47PppController *CommandListener::sPppCtrl = NULL; 48PanController *CommandListener::sPanCtrl = NULL; 49SoftapController *CommandListener::sSoftapCtrl = NULL; 50BandwidthController * CommandListener::sBandwidthCtrl = NULL; 51IdletimerController * CommandListener::sIdletimerCtrl = NULL; 52ResolverController *CommandListener::sResolverCtrl = NULL; 53SecondaryTableController *CommandListener::sSecondaryTableCtrl = NULL; 54 55CommandListener::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 113CommandListener::InterfaceCmd::InterfaceCmd() : 114 NetdCommand("interface") { 115} 116 117int 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 133int 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 < 4) { 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 int index = 5; 348 349 ifc_init(); 350 351 if (!inet_aton(argv[3], &addr)) { 352 // Handle flags only case 353 index = 3; 354 } else { 355 if (ifc_set_addr(argv[2], addr.s_addr)) { 356 cli->sendMsg(ResponseCode::OperationFailed, "Failed to set address", true); 357 ifc_close(); 358 return 0; 359 } 360 361 // Set prefix length on a non zero address 362 if (addr.s_addr != 0 && ifc_set_prefixLength(argv[2], atoi(argv[4]))) { 363 cli->sendMsg(ResponseCode::OperationFailed, "Failed to set prefixLength", true); 364 ifc_close(); 365 return 0; 366 } 367 } 368 369 /* Process flags */ 370 for (int i = index; i < argc; i++) { 371 char *flag = argv[i]; 372 if (!strcmp(flag, "up")) { 373 ALOGD("Trying to bring up %s", argv[2]); 374 if (ifc_up(argv[2])) { 375 ALOGE("Error upping interface"); 376 cli->sendMsg(ResponseCode::OperationFailed, "Failed to up interface", true); 377 ifc_close(); 378 return 0; 379 } 380 } else if (!strcmp(flag, "down")) { 381 ALOGD("Trying to bring down %s", argv[2]); 382 if (ifc_down(argv[2])) { 383 ALOGE("Error downing interface"); 384 cli->sendMsg(ResponseCode::OperationFailed, "Failed to down interface", true); 385 ifc_close(); 386 return 0; 387 } 388 } else if (!strcmp(flag, "broadcast")) { 389 // currently ignored 390 } else if (!strcmp(flag, "multicast")) { 391 // currently ignored 392 } else if (!strcmp(flag, "running")) { 393 // currently ignored 394 } else if (!strcmp(flag, "loopback")) { 395 // currently ignored 396 } else if (!strcmp(flag, "point-to-point")) { 397 // currently ignored 398 } else { 399 cli->sendMsg(ResponseCode::CommandParameterError, "Flag unsupported", false); 400 ifc_close(); 401 return 0; 402 } 403 } 404 405 cli->sendMsg(ResponseCode::CommandOkay, "Interface configuration set", false); 406 ifc_close(); 407 return 0; 408 } else if (!strcmp(argv[1], "clearaddrs")) { 409 // arglist: iface 410 ALOGD("Clearing all IP addresses on %s", argv[2]); 411 412 ifc_clear_addresses(argv[2]); 413 414 cli->sendMsg(ResponseCode::CommandOkay, "Interface IP addresses cleared", false); 415 return 0; 416 } else if (!strcmp(argv[1], "ipv6privacyextensions")) { 417 if (argc != 4) { 418 cli->sendMsg(ResponseCode::CommandSyntaxError, 419 "Usage: interface ipv6privacyextensions <interface> <enable|disable>", 420 false); 421 return 0; 422 } 423 424 char *tmp; 425 asprintf(&tmp, "/proc/sys/net/ipv6/conf/%s/use_tempaddr", argv[2]); 426 427 if (writeFile(tmp, !strncmp(argv[3], "enable", 7) ? "2" : "0", 1) < 0) { 428 free(tmp); 429 cli->sendMsg(ResponseCode::OperationFailed, 430 "Failed to set ipv6 privacy extensions", true); 431 return 0; 432 } 433 434 free(tmp); 435 cli->sendMsg(ResponseCode::CommandOkay, "IPv6 privacy extensions changed", false); 436 return 0; 437 } else if (!strcmp(argv[1], "ipv6")) { 438 if (argc != 4) { 439 cli->sendMsg(ResponseCode::CommandSyntaxError, 440 "Usage: interface ipv6 <interface> <enable|disable>", 441 false); 442 return 0; 443 } 444 445 char *tmp; 446 asprintf(&tmp, "/proc/sys/net/ipv6/conf/%s/disable_ipv6", argv[2]); 447 448 if (writeFile(tmp, !strncmp(argv[3], "enable", 7) ? "0" : "1", 1) < 0) { 449 free(tmp); 450 cli->sendMsg(ResponseCode::OperationFailed, 451 "Failed to change IPv6 state", true); 452 return 0; 453 } 454 455 free(tmp); 456 cli->sendMsg(ResponseCode::CommandOkay, "IPv6 state changed", false); 457 return 0; 458 } else { 459 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown interface cmd", false); 460 return 0; 461 } 462 } 463 return 0; 464} 465 466 467CommandListener::ListTtysCmd::ListTtysCmd() : 468 NetdCommand("list_ttys") { 469} 470 471int CommandListener::ListTtysCmd::runCommand(SocketClient *cli, 472 int argc, char **argv) { 473 TtyCollection *tlist = sPppCtrl->getTtyList(); 474 TtyCollection::iterator it; 475 476 for (it = tlist->begin(); it != tlist->end(); ++it) { 477 cli->sendMsg(ResponseCode::TtyListResult, *it, false); 478 } 479 480 cli->sendMsg(ResponseCode::CommandOkay, "Ttys listed.", false); 481 return 0; 482} 483 484CommandListener::IpFwdCmd::IpFwdCmd() : 485 NetdCommand("ipfwd") { 486} 487 488int CommandListener::IpFwdCmd::runCommand(SocketClient *cli, 489 int argc, char **argv) { 490 int rc = 0; 491 492 if (argc < 2) { 493 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); 494 return 0; 495 } 496 497 if (!strcmp(argv[1], "status")) { 498 char *tmp = NULL; 499 500 asprintf(&tmp, "Forwarding %s", (sTetherCtrl->getIpFwdEnabled() ? "enabled" : "disabled")); 501 cli->sendMsg(ResponseCode::IpFwdStatusResult, tmp, false); 502 free(tmp); 503 return 0; 504 } else if (!strcmp(argv[1], "enable")) { 505 rc = sTetherCtrl->setIpFwdEnabled(true); 506 } else if (!strcmp(argv[1], "disable")) { 507 rc = sTetherCtrl->setIpFwdEnabled(false); 508 } else { 509 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown ipfwd cmd", false); 510 return 0; 511 } 512 513 if (!rc) { 514 cli->sendMsg(ResponseCode::CommandOkay, "ipfwd operation succeeded", false); 515 } else { 516 cli->sendMsg(ResponseCode::OperationFailed, "ipfwd operation failed", true); 517 } 518 519 return 0; 520} 521 522CommandListener::TetherCmd::TetherCmd() : 523 NetdCommand("tether") { 524} 525 526int CommandListener::TetherCmd::runCommand(SocketClient *cli, 527 int argc, char **argv) { 528 int rc = 0; 529 530 if (argc < 2) { 531 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); 532 return 0; 533 } 534 535 if (!strcmp(argv[1], "stop")) { 536 rc = sTetherCtrl->stopTethering(); 537 } else if (!strcmp(argv[1], "status")) { 538 char *tmp = NULL; 539 540 asprintf(&tmp, "Tethering services %s", 541 (sTetherCtrl->isTetheringStarted() ? "started" : "stopped")); 542 cli->sendMsg(ResponseCode::TetherStatusResult, tmp, false); 543 free(tmp); 544 return 0; 545 } else { 546 /* 547 * These commands take a minimum of 4 arguments 548 */ 549 if (argc < 4) { 550 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); 551 return 0; 552 } 553 554 if (!strcmp(argv[1], "start")) { 555 if (argc % 2 == 1) { 556 cli->sendMsg(ResponseCode::CommandSyntaxError, "Bad number of arguments", false); 557 return 0; 558 } 559 560 int num_addrs = argc - 2; 561 int arg_index = 2; 562 int array_index = 0; 563 in_addr *addrs = (in_addr *)malloc(sizeof(in_addr) * num_addrs); 564 while (array_index < num_addrs) { 565 if (!inet_aton(argv[arg_index++], &(addrs[array_index++]))) { 566 cli->sendMsg(ResponseCode::CommandParameterError, "Invalid address", false); 567 free(addrs); 568 return 0; 569 } 570 } 571 rc = sTetherCtrl->startTethering(num_addrs, addrs); 572 free(addrs); 573 } else if (!strcmp(argv[1], "interface")) { 574 if (!strcmp(argv[2], "add")) { 575 rc = sTetherCtrl->tetherInterface(argv[3]); 576 } else if (!strcmp(argv[2], "remove")) { 577 rc = sTetherCtrl->untetherInterface(argv[3]); 578 } else if (!strcmp(argv[2], "list")) { 579 InterfaceCollection *ilist = sTetherCtrl->getTetheredInterfaceList(); 580 InterfaceCollection::iterator it; 581 582 for (it = ilist->begin(); it != ilist->end(); ++it) { 583 cli->sendMsg(ResponseCode::TetherInterfaceListResult, *it, false); 584 } 585 } else { 586 cli->sendMsg(ResponseCode::CommandParameterError, 587 "Unknown tether interface operation", false); 588 return 0; 589 } 590 } else if (!strcmp(argv[1], "dns")) { 591 if (!strcmp(argv[2], "set")) { 592 rc = sTetherCtrl->setDnsForwarders(&argv[3], argc - 3); 593 } else if (!strcmp(argv[2], "list")) { 594 NetAddressCollection *dlist = sTetherCtrl->getDnsForwarders(); 595 NetAddressCollection::iterator it; 596 597 for (it = dlist->begin(); it != dlist->end(); ++it) { 598 cli->sendMsg(ResponseCode::TetherDnsFwdTgtListResult, inet_ntoa(*it), false); 599 } 600 } else { 601 cli->sendMsg(ResponseCode::CommandParameterError, 602 "Unknown tether interface operation", false); 603 return 0; 604 } 605 } else { 606 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown tether cmd", false); 607 return 0; 608 } 609 } 610 611 if (!rc) { 612 cli->sendMsg(ResponseCode::CommandOkay, "Tether operation succeeded", false); 613 } else { 614 cli->sendMsg(ResponseCode::OperationFailed, "Tether operation failed", true); 615 } 616 617 return 0; 618} 619 620CommandListener::NatCmd::NatCmd() : 621 NetdCommand("nat") { 622} 623 624int CommandListener::NatCmd::runCommand(SocketClient *cli, 625 int argc, char **argv) { 626 int rc = 0; 627 628 if (argc < 5) { 629 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); 630 return 0; 631 } 632 633 if (!strcmp(argv[1], "enable")) { 634 rc = sNatCtrl->enableNat(argc, argv); 635 if(!rc) { 636 /* Ignore ifaces for now. */ 637 rc = sBandwidthCtrl->setGlobalAlertInForwardChain(); 638 } 639 } else if (!strcmp(argv[1], "disable")) { 640 /* Ignore ifaces for now. */ 641 rc = sBandwidthCtrl->removeGlobalAlertInForwardChain(); 642 rc |= sNatCtrl->disableNat(argc, argv); 643 } else { 644 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown nat cmd", false); 645 return 0; 646 } 647 648 if (!rc) { 649 cli->sendMsg(ResponseCode::CommandOkay, "Nat operation succeeded", false); 650 } else { 651 cli->sendMsg(ResponseCode::OperationFailed, "Nat operation failed", true); 652 } 653 654 return 0; 655} 656 657CommandListener::PppdCmd::PppdCmd() : 658 NetdCommand("pppd") { 659} 660 661int CommandListener::PppdCmd::runCommand(SocketClient *cli, 662 int argc, char **argv) { 663 int rc = 0; 664 665 if (argc < 3) { 666 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); 667 return 0; 668 } 669 670 if (!strcmp(argv[1], "attach")) { 671 struct in_addr l, r, dns1, dns2; 672 673 memset(&dns1, sizeof(struct in_addr), 0); 674 memset(&dns2, sizeof(struct in_addr), 0); 675 676 if (!inet_aton(argv[3], &l)) { 677 cli->sendMsg(ResponseCode::CommandParameterError, "Invalid local address", false); 678 return 0; 679 } 680 if (!inet_aton(argv[4], &r)) { 681 cli->sendMsg(ResponseCode::CommandParameterError, "Invalid remote address", false); 682 return 0; 683 } 684 if ((argc > 3) && (!inet_aton(argv[5], &dns1))) { 685 cli->sendMsg(ResponseCode::CommandParameterError, "Invalid dns1 address", false); 686 return 0; 687 } 688 if ((argc > 4) && (!inet_aton(argv[6], &dns2))) { 689 cli->sendMsg(ResponseCode::CommandParameterError, "Invalid dns2 address", false); 690 return 0; 691 } 692 rc = sPppCtrl->attachPppd(argv[2], l, r, dns1, dns2); 693 } else if (!strcmp(argv[1], "detach")) { 694 rc = sPppCtrl->detachPppd(argv[2]); 695 } else { 696 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown pppd cmd", false); 697 return 0; 698 } 699 700 if (!rc) { 701 cli->sendMsg(ResponseCode::CommandOkay, "Pppd operation succeeded", false); 702 } else { 703 cli->sendMsg(ResponseCode::OperationFailed, "Pppd operation failed", true); 704 } 705 706 return 0; 707} 708 709CommandListener::PanCmd::PanCmd() : 710 NetdCommand("pan") { 711} 712 713int CommandListener::PanCmd::runCommand(SocketClient *cli, 714 int argc, char **argv) { 715 int rc = 0; 716 717 if (argc < 2) { 718 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); 719 return 0; 720 } 721 722 if (!strcmp(argv[1], "start")) { 723 rc = sPanCtrl->startPan(); 724 } else if (!strcmp(argv[1], "stop")) { 725 rc = sPanCtrl->stopPan(); 726 } else if (!strcmp(argv[1], "status")) { 727 char *tmp = NULL; 728 729 asprintf(&tmp, "Pan services %s", 730 (sPanCtrl->isPanStarted() ? "started" : "stopped")); 731 cli->sendMsg(ResponseCode::PanStatusResult, tmp, false); 732 free(tmp); 733 return 0; 734 } else { 735 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown pan cmd", false); 736 return 0; 737 } 738 739 if (!rc) { 740 cli->sendMsg(ResponseCode::CommandOkay, "Pan operation succeeded", false); 741 } else { 742 cli->sendMsg(ResponseCode::OperationFailed, "Pan operation failed", true); 743 } 744 745 return 0; 746} 747 748CommandListener::SoftapCmd::SoftapCmd() : 749 NetdCommand("softap") { 750} 751 752int CommandListener::SoftapCmd::runCommand(SocketClient *cli, 753 int argc, char **argv) { 754 int rc = 0, flag = 0; 755 char *retbuf = NULL; 756 757 if (argc < 2) { 758 cli->sendMsg(ResponseCode::CommandSyntaxError, "Softap Missing argument", false); 759 return 0; 760 } 761 762 if (!strcmp(argv[1], "startap")) { 763 rc = sSoftapCtrl->startSoftap(); 764 } else if (!strcmp(argv[1], "stopap")) { 765 rc = sSoftapCtrl->stopSoftap(); 766 } else if (!strcmp(argv[1], "fwreload")) { 767 rc = sSoftapCtrl->fwReloadSoftap(argc, argv); 768 } else if (!strcmp(argv[1], "clients")) { 769 rc = sSoftapCtrl->clientsSoftap(&retbuf); 770 if (!rc) { 771 cli->sendMsg(ResponseCode::CommandOkay, retbuf, false); 772 free(retbuf); 773 return 0; 774 } 775 } else if (!strcmp(argv[1], "status")) { 776 asprintf(&retbuf, "Softap service %s", 777 (sSoftapCtrl->isSoftapStarted() ? "started" : "stopped")); 778 cli->sendMsg(ResponseCode::SoftapStatusResult, retbuf, false); 779 free(retbuf); 780 return 0; 781 } else if (!strcmp(argv[1], "set")) { 782 rc = sSoftapCtrl->setSoftap(argc, argv); 783 } else { 784 cli->sendMsg(ResponseCode::CommandSyntaxError, "Softap Unknown cmd", false); 785 return 0; 786 } 787 788 if (!rc) { 789 cli->sendMsg(ResponseCode::CommandOkay, "Softap operation succeeded", false); 790 } else { 791 cli->sendMsg(ResponseCode::OperationFailed, "Softap operation failed", true); 792 } 793 794 return 0; 795} 796 797CommandListener::ResolverCmd::ResolverCmd() : 798 NetdCommand("resolver") { 799} 800 801int CommandListener::ResolverCmd::runCommand(SocketClient *cli, int argc, char **argv) { 802 int rc = 0; 803 struct in_addr addr; 804 805 if (argc < 2) { 806 cli->sendMsg(ResponseCode::CommandSyntaxError, "Resolver missing arguments", false); 807 return 0; 808 } 809 810 if (!strcmp(argv[1], "setdefaultif")) { // "resolver setdefaultif <iface>" 811 if (argc == 3) { 812 rc = sResolverCtrl->setDefaultInterface(argv[2]); 813 } else { 814 cli->sendMsg(ResponseCode::CommandSyntaxError, 815 "Wrong number of arguments to resolver setdefaultif", false); 816 return 0; 817 } 818 } else if (!strcmp(argv[1], "setifdns")) { // "resolver setifdns <iface> <dns1> <dns2> ..." 819 if (argc >= 4) { 820 rc = sResolverCtrl->setInterfaceDnsServers(argv[2], &argv[3], argc - 3); 821 } else { 822 cli->sendMsg(ResponseCode::CommandSyntaxError, 823 "Wrong number of arguments to resolver setifdns", false); 824 return 0; 825 } 826 827 // set the address of the interface to which the name servers 828 // are bound. Required in order to bind to right interface when 829 // doing the dns query. 830 if (!rc) { 831 ifc_init(); 832 ifc_get_info(argv[2], &addr.s_addr, NULL, 0); 833 834 rc = sResolverCtrl->setInterfaceAddress(argv[2], &addr); 835 } 836 } else if (!strcmp(argv[1], "flushdefaultif")) { // "resolver flushdefaultif" 837 if (argc == 2) { 838 rc = sResolverCtrl->flushDefaultDnsCache(); 839 } else { 840 cli->sendMsg(ResponseCode::CommandSyntaxError, 841 "Wrong number of arguments to resolver flushdefaultif", false); 842 return 0; 843 } 844 } else if (!strcmp(argv[1], "flushif")) { // "resolver flushif <iface>" 845 if (argc == 3) { 846 rc = sResolverCtrl->flushInterfaceDnsCache(argv[2]); 847 } else { 848 cli->sendMsg(ResponseCode::CommandSyntaxError, 849 "Wrong number of arguments to resolver setdefaultif", false); 850 return 0; 851 } 852 } else { 853 cli->sendMsg(ResponseCode::CommandSyntaxError,"Resolver unknown command", false); 854 return 0; 855 } 856 857 if (!rc) { 858 cli->sendMsg(ResponseCode::CommandOkay, "Resolver command succeeded", false); 859 } else { 860 cli->sendMsg(ResponseCode::OperationFailed, "Resolver command failed", true); 861 } 862 863 return 0; 864} 865 866int CommandListener::readInterfaceCounters(const char *iface, unsigned long *rx, unsigned long *tx) { 867 FILE *fp = fopen("/proc/net/dev", "r"); 868 if (!fp) { 869 ALOGE("Failed to open /proc/net/dev (%s)", strerror(errno)); 870 return -1; 871 } 872 873 char buffer[512]; 874 875 fgets(buffer, sizeof(buffer), fp); // Header 1 876 fgets(buffer, sizeof(buffer), fp); // Header 2 877 while(fgets(buffer, sizeof(buffer), fp)) { 878 buffer[strlen(buffer)-1] = '\0'; 879 880 char name[31]; 881 unsigned long d; 882 sscanf(buffer, "%30s %lu %lu %lu %lu %lu %lu %lu %lu %lu", 883 name, rx, &d, &d, &d, &d, &d, &d, &d, tx); 884 char *rxString = strchr(name, ':'); 885 *rxString = '\0'; 886 rxString++; 887 // when the rx count gets too big it changes from "name: 999" to "name:1000" 888 // and the sscanf munge the two together. Detect that and fix 889 // note that all the %lu will be off by one and the real tx value will be in d 890 if (*rxString != '\0') { 891 *tx = d; 892 sscanf(rxString, "%20lu", rx); 893 } 894 if (strcmp(name, iface)) { 895 continue; 896 } 897 fclose(fp); 898 return 0; 899 } 900 901 fclose(fp); 902 *rx = 0; 903 *tx = 0; 904 return 0; 905} 906 907CommandListener::BandwidthControlCmd::BandwidthControlCmd() : 908 NetdCommand("bandwidth") { 909} 910 911void CommandListener::BandwidthControlCmd::sendGenericSyntaxError(SocketClient *cli, const char *usageMsg) { 912 char *msg; 913 asprintf(&msg, "Usage: bandwidth %s", usageMsg); 914 cli->sendMsg(ResponseCode::CommandSyntaxError, msg, false); 915 free(msg); 916} 917 918void CommandListener::BandwidthControlCmd::sendGenericOkFail(SocketClient *cli, int cond) { 919 if (!cond) { 920 cli->sendMsg(ResponseCode::CommandOkay, "Bandwidth command succeeeded", false); 921 } else { 922 cli->sendMsg(ResponseCode::OperationFailed, "Bandwidth command failed", false); 923 } 924} 925 926void CommandListener::BandwidthControlCmd::sendGenericOpFailed(SocketClient *cli, const char *errMsg) { 927 cli->sendMsg(ResponseCode::OperationFailed, errMsg, false); 928} 929 930int CommandListener::BandwidthControlCmd::runCommand(SocketClient *cli, int argc, char **argv) { 931 if (argc < 2) { 932 sendGenericSyntaxError(cli, "<cmds> <args...>"); 933 return 0; 934 } 935 936 ALOGV("bwctrlcmd: argc=%d %s %s ...", argc, argv[0], argv[1]); 937 938 if (!strcmp(argv[1], "enable")) { 939 int rc = sBandwidthCtrl->enableBandwidthControl(true); 940 sendGenericOkFail(cli, rc); 941 return 0; 942 943 } 944 if (!strcmp(argv[1], "disable")) { 945 int rc = sBandwidthCtrl->disableBandwidthControl(); 946 sendGenericOkFail(cli, rc); 947 return 0; 948 949 } 950 if (!strcmp(argv[1], "removequota") || !strcmp(argv[1], "rq")) { 951 if (argc != 3) { 952 sendGenericSyntaxError(cli, "removequota <interface>"); 953 return 0; 954 } 955 int rc = sBandwidthCtrl->removeInterfaceSharedQuota(argv[2]); 956 sendGenericOkFail(cli, rc); 957 return 0; 958 959 } 960 if (!strcmp(argv[1], "getquota") || !strcmp(argv[1], "gq")) { 961 int64_t bytes; 962 if (argc != 2) { 963 sendGenericSyntaxError(cli, "getquota"); 964 return 0; 965 } 966 int rc = sBandwidthCtrl->getInterfaceSharedQuota(&bytes); 967 if (rc) { 968 sendGenericOpFailed(cli, "Failed to get quota"); 969 return 0; 970 } 971 972 char *msg; 973 asprintf(&msg, "%lld", bytes); 974 cli->sendMsg(ResponseCode::QuotaCounterResult, msg, false); 975 free(msg); 976 return 0; 977 978 } 979 if (!strcmp(argv[1], "getiquota") || !strcmp(argv[1], "giq")) { 980 int64_t bytes; 981 if (argc != 3) { 982 sendGenericSyntaxError(cli, "getiquota <iface>"); 983 return 0; 984 } 985 986 int rc = sBandwidthCtrl->getInterfaceQuota(argv[2], &bytes); 987 if (rc) { 988 sendGenericOpFailed(cli, "Failed to get quota"); 989 return 0; 990 } 991 char *msg; 992 asprintf(&msg, "%lld", bytes); 993 cli->sendMsg(ResponseCode::QuotaCounterResult, msg, false); 994 free(msg); 995 return 0; 996 997 } 998 if (!strcmp(argv[1], "setquota") || !strcmp(argv[1], "sq")) { 999 if (argc != 4) { 1000 sendGenericSyntaxError(cli, "setquota <interface> <bytes>"); 1001 return 0; 1002 } 1003 int rc = sBandwidthCtrl->setInterfaceSharedQuota(argv[2], atoll(argv[3])); 1004 sendGenericOkFail(cli, rc); 1005 return 0; 1006 } 1007 if (!strcmp(argv[1], "setquotas") || !strcmp(argv[1], "sqs")) { 1008 int rc; 1009 if (argc < 4) { 1010 sendGenericSyntaxError(cli, "setquotas <bytes> <interface> ..."); 1011 return 0; 1012 } 1013 1014 for (int q = 3; argc >= 4; q++, argc--) { 1015 rc = sBandwidthCtrl->setInterfaceSharedQuota(argv[q], atoll(argv[2])); 1016 if (rc) { 1017 char *msg; 1018 asprintf(&msg, "bandwidth setquotas %s %s failed", argv[2], argv[q]); 1019 cli->sendMsg(ResponseCode::OperationFailed, 1020 msg, false); 1021 free(msg); 1022 return 0; 1023 } 1024 } 1025 sendGenericOkFail(cli, rc); 1026 return 0; 1027 1028 } 1029 if (!strcmp(argv[1], "removequotas") || !strcmp(argv[1], "rqs")) { 1030 int rc; 1031 if (argc < 3) { 1032 sendGenericSyntaxError(cli, "removequotas <interface> ..."); 1033 return 0; 1034 } 1035 1036 for (int q = 2; argc >= 3; q++, argc--) { 1037 rc = sBandwidthCtrl->removeInterfaceSharedQuota(argv[q]); 1038 if (rc) { 1039 char *msg; 1040 asprintf(&msg, "bandwidth removequotas %s failed", argv[q]); 1041 cli->sendMsg(ResponseCode::OperationFailed, 1042 msg, false); 1043 free(msg); 1044 return 0; 1045 } 1046 } 1047 sendGenericOkFail(cli, rc); 1048 return 0; 1049 1050 } 1051 if (!strcmp(argv[1], "removeiquota") || !strcmp(argv[1], "riq")) { 1052 if (argc != 3) { 1053 sendGenericSyntaxError(cli, "removeiquota <interface>"); 1054 return 0; 1055 } 1056 int rc = sBandwidthCtrl->removeInterfaceQuota(argv[2]); 1057 sendGenericOkFail(cli, rc); 1058 return 0; 1059 1060 } 1061 if (!strcmp(argv[1], "setiquota") || !strcmp(argv[1], "siq")) { 1062 if (argc != 4) { 1063 sendGenericSyntaxError(cli, "setiquota <interface> <bytes>"); 1064 return 0; 1065 } 1066 int rc = sBandwidthCtrl->setInterfaceQuota(argv[2], atoll(argv[3])); 1067 sendGenericOkFail(cli, rc); 1068 return 0; 1069 1070 } 1071 if (!strcmp(argv[1], "addnaughtyapps") || !strcmp(argv[1], "ana")) { 1072 if (argc < 3) { 1073 sendGenericSyntaxError(cli, "addnaughtyapps <appUid> ..."); 1074 return 0; 1075 } 1076 int rc = sBandwidthCtrl->addNaughtyApps(argc - 2, argv + 2); 1077 sendGenericOkFail(cli, rc); 1078 return 0; 1079 1080 1081 } 1082 if (!strcmp(argv[1], "removenaughtyapps") || !strcmp(argv[1], "rna")) { 1083 if (argc < 3) { 1084 sendGenericSyntaxError(cli, "removenaughtyapps <appUid> ..."); 1085 return 0; 1086 } 1087 int rc = sBandwidthCtrl->removeNaughtyApps(argc - 2, argv + 2); 1088 sendGenericOkFail(cli, rc); 1089 return 0; 1090 1091 } 1092 if (!strcmp(argv[1], "setglobalalert") || !strcmp(argv[1], "sga")) { 1093 if (argc != 3) { 1094 sendGenericSyntaxError(cli, "setglobalalert <bytes>"); 1095 return 0; 1096 } 1097 int rc = sBandwidthCtrl->setGlobalAlert(atoll(argv[2])); 1098 sendGenericOkFail(cli, rc); 1099 return 0; 1100 1101 } 1102 if (!strcmp(argv[1], "debugsettetherglobalalert") || !strcmp(argv[1], "dstga")) { 1103 if (argc != 4) { 1104 sendGenericSyntaxError(cli, "debugsettetherglobalalert <interface0> <interface1>"); 1105 return 0; 1106 } 1107 /* We ignore the interfaces for now. */ 1108 int rc = sBandwidthCtrl->setGlobalAlertInForwardChain(); 1109 sendGenericOkFail(cli, rc); 1110 return 0; 1111 1112 } 1113 if (!strcmp(argv[1], "removeglobalalert") || !strcmp(argv[1], "rga")) { 1114 if (argc != 2) { 1115 sendGenericSyntaxError(cli, "removeglobalalert"); 1116 return 0; 1117 } 1118 int rc = sBandwidthCtrl->removeGlobalAlert(); 1119 sendGenericOkFail(cli, rc); 1120 return 0; 1121 1122 } 1123 if (!strcmp(argv[1], "debugremovetetherglobalalert") || !strcmp(argv[1], "drtga")) { 1124 if (argc != 4) { 1125 sendGenericSyntaxError(cli, "debugremovetetherglobalalert <interface0> <interface1>"); 1126 return 0; 1127 } 1128 /* We ignore the interfaces for now. */ 1129 int rc = sBandwidthCtrl->removeGlobalAlertInForwardChain(); 1130 sendGenericOkFail(cli, rc); 1131 return 0; 1132 1133 } 1134 if (!strcmp(argv[1], "setsharedalert") || !strcmp(argv[1], "ssa")) { 1135 if (argc != 3) { 1136 sendGenericSyntaxError(cli, "setsharedalert <bytes>"); 1137 return 0; 1138 } 1139 int rc = sBandwidthCtrl->setSharedAlert(atoll(argv[2])); 1140 sendGenericOkFail(cli, rc); 1141 return 0; 1142 1143 } 1144 if (!strcmp(argv[1], "removesharedalert") || !strcmp(argv[1], "rsa")) { 1145 if (argc != 2) { 1146 sendGenericSyntaxError(cli, "removesharedalert"); 1147 return 0; 1148 } 1149 int rc = sBandwidthCtrl->removeSharedAlert(); 1150 sendGenericOkFail(cli, rc); 1151 return 0; 1152 1153 } 1154 if (!strcmp(argv[1], "setinterfacealert") || !strcmp(argv[1], "sia")) { 1155 if (argc != 4) { 1156 sendGenericSyntaxError(cli, "setinterfacealert <interface> <bytes>"); 1157 return 0; 1158 } 1159 int rc = sBandwidthCtrl->setInterfaceAlert(argv[2], atoll(argv[3])); 1160 sendGenericOkFail(cli, rc); 1161 return 0; 1162 1163 } 1164 if (!strcmp(argv[1], "removeinterfacealert") || !strcmp(argv[1], "ria")) { 1165 if (argc != 3) { 1166 sendGenericSyntaxError(cli, "removeinterfacealert <interface>"); 1167 return 0; 1168 } 1169 int rc = sBandwidthCtrl->removeInterfaceAlert(argv[2]); 1170 sendGenericOkFail(cli, rc); 1171 return 0; 1172 1173 } 1174 if (!strcmp(argv[1], "gettetherstats") || !strcmp(argv[1], "gts")) { 1175 BandwidthController::TetherStats tetherStats; 1176 std::string extraProcessingInfo = ""; 1177 if (argc != 4) { 1178 sendGenericSyntaxError(cli, "gettetherstats <interface0> <interface1>"); 1179 return 0; 1180 } 1181 1182 tetherStats.ifaceIn = argv[2]; 1183 tetherStats.ifaceOut = argv[3]; 1184 int rc = sBandwidthCtrl->getTetherStats(tetherStats, extraProcessingInfo); 1185 if (rc) { 1186 extraProcessingInfo.insert(0, "Failed to get tethering stats.\n"); 1187 sendGenericOpFailed(cli, extraProcessingInfo.c_str()); 1188 return 0; 1189 } 1190 1191 char *msg = tetherStats.getStatsLine(); 1192 cli->sendMsg(ResponseCode::TetheringStatsResult, msg, false); 1193 free(msg); 1194 return 0; 1195 1196 } 1197 1198 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown bandwidth cmd", false); 1199 return 0; 1200} 1201 1202CommandListener::IdletimerControlCmd::IdletimerControlCmd() : 1203 NetdCommand("idletimer") { 1204} 1205 1206int CommandListener::IdletimerControlCmd::runCommand(SocketClient *cli, int argc, char **argv) { 1207 // TODO(ashish): Change the error statements 1208 if (argc < 2) { 1209 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); 1210 return 0; 1211 } 1212 1213 ALOGV("idletimerctrlcmd: argc=%d %s %s ...", argc, argv[0], argv[1]); 1214 1215 if (!strcmp(argv[1], "enable")) { 1216 if (0 != sIdletimerCtrl->enableIdletimerControl()) { 1217 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); 1218 } else { 1219 cli->sendMsg(ResponseCode::CommandOkay, "Enable success", false); 1220 } 1221 return 0; 1222 1223 } 1224 if (!strcmp(argv[1], "disable")) { 1225 if (0 != sIdletimerCtrl->disableIdletimerControl()) { 1226 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); 1227 } else { 1228 cli->sendMsg(ResponseCode::CommandOkay, "Disable success", false); 1229 } 1230 return 0; 1231 } 1232 if (!strcmp(argv[1], "add")) { 1233 if (argc != 5) { 1234 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); 1235 return 0; 1236 } 1237 if(0 != sIdletimerCtrl->addInterfaceIdletimer( 1238 argv[2], atoi(argv[3]), argv[4])) { 1239 cli->sendMsg(ResponseCode::OperationFailed, "Failed to add interface", false); 1240 } else { 1241 cli->sendMsg(ResponseCode::CommandOkay, "Add success", false); 1242 } 1243 return 0; 1244 } 1245 if (!strcmp(argv[1], "remove")) { 1246 if (argc != 5) { 1247 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false); 1248 return 0; 1249 } 1250 // ashish: fixme timeout 1251 if (0 != sIdletimerCtrl->removeInterfaceIdletimer( 1252 argv[2], atoi(argv[3]), argv[4])) { 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