command.c revision 40622
1/* 2 * PPP User command processing module 3 * 4 * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5 * 6 * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 7 * 8 * Redistribution and use in source and binary forms are permitted 9 * provided that the above copyright notice and this paragraph are 10 * duplicated in all such forms and that any documentation, 11 * advertising materials, and other materials related to such 12 * distribution and use acknowledge that the software was developed 13 * by the Internet Initiative Japan, Inc. The name of the 14 * IIJ may not be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 * 20 * $Id: command.c,v 1.168 1998/10/22 02:32:48 brian Exp $ 21 * 22 */ 23#include <sys/types.h> 24#include <netinet/in_systm.h> 25#include <netinet/in.h> 26#include <netinet/ip.h> 27#include <arpa/inet.h> 28#include <sys/socket.h> 29#include <net/route.h> 30#include <netdb.h> 31#include <sys/un.h> 32 33#include <ctype.h> 34#include <errno.h> 35#include <fcntl.h> 36#include <paths.h> 37#include <stdio.h> 38#include <stdlib.h> 39#include <string.h> 40#include <sys/wait.h> 41#include <termios.h> 42#include <unistd.h> 43 44#ifndef NOALIAS 45#ifdef __OpenBSD__ 46#include "alias.h" 47#else 48#include <alias.h> 49#endif 50#endif 51#include "defs.h" 52#include "command.h" 53#include "mbuf.h" 54#include "log.h" 55#include "timer.h" 56#include "fsm.h" 57#include "lcp.h" 58#include "iplist.h" 59#include "throughput.h" 60#include "slcompress.h" 61#include "lqr.h" 62#include "hdlc.h" 63#include "ipcp.h" 64#include "modem.h" 65#ifndef NOALIAS 66#include "alias_cmd.h" 67#endif 68#include "systems.h" 69#include "filter.h" 70#include "descriptor.h" 71#include "main.h" 72#include "route.h" 73#include "ccp.h" 74#include "auth.h" 75#include "async.h" 76#include "link.h" 77#include "physical.h" 78#include "mp.h" 79#include "bundle.h" 80#include "server.h" 81#include "prompt.h" 82#include "chat.h" 83#include "chap.h" 84#include "cbcp.h" 85#include "datalink.h" 86#include "iface.h" 87 88/* ``set'' values */ 89#define VAR_AUTHKEY 0 90#define VAR_DIAL 1 91#define VAR_LOGIN 2 92#define VAR_AUTHNAME 3 93#define VAR_AUTOLOAD 4 94#define VAR_WINSIZE 5 95#define VAR_DEVICE 6 96#define VAR_ACCMAP 7 97#define VAR_MRRU 8 98#define VAR_MRU 9 99#define VAR_MTU 10 100#define VAR_OPENMODE 11 101#define VAR_PHONE 12 102#define VAR_HANGUP 13 103#define VAR_IDLETIMEOUT 14 104#define VAR_LQRPERIOD 15 105#define VAR_LCPRETRY 16 106#define VAR_CHAPRETRY 17 107#define VAR_PAPRETRY 18 108#define VAR_CCPRETRY 19 109#define VAR_IPCPRETRY 20 110#define VAR_DNS 21 111#define VAR_NBNS 22 112#define VAR_MODE 23 113#define VAR_CALLBACK 24 114#define VAR_CBCP 25 115#define VAR_CHOKED 26 116 117/* ``accept|deny|disable|enable'' masks */ 118#define NEG_HISMASK (1) 119#define NEG_MYMASK (2) 120 121/* ``accept|deny|disable|enable'' values */ 122#define NEG_ACFCOMP 40 123#define NEG_CHAP 41 124#define NEG_DEFLATE 42 125#define NEG_LQR 43 126#define NEG_PAP 44 127#define NEG_PPPDDEFLATE 45 128#define NEG_PRED1 46 129#define NEG_PROTOCOMP 47 130#define NEG_SHORTSEQ 48 131#define NEG_VJCOMP 49 132#define NEG_DNS 50 133 134const char Version[] = "2.0"; 135const char VersionDate[] = "$Date: 1998/10/22 02:32:48 $"; 136 137static int ShowCommand(struct cmdargs const *); 138static int TerminalCommand(struct cmdargs const *); 139static int QuitCommand(struct cmdargs const *); 140static int OpenCommand(struct cmdargs const *); 141static int CloseCommand(struct cmdargs const *); 142static int DownCommand(struct cmdargs const *); 143static int SetCommand(struct cmdargs const *); 144static int LinkCommand(struct cmdargs const *); 145static int AddCommand(struct cmdargs const *); 146static int DeleteCommand(struct cmdargs const *); 147static int NegotiateCommand(struct cmdargs const *); 148static int ClearCommand(struct cmdargs const *); 149static int RunListCommand(struct cmdargs const *); 150static int IfaceAddCommand(struct cmdargs const *); 151static int IfaceDeleteCommand(struct cmdargs const *); 152static int IfaceClearCommand(struct cmdargs const *); 153#ifndef NOALIAS 154static int AliasEnable(struct cmdargs const *); 155static int AliasOption(struct cmdargs const *); 156#endif 157 158static const char * 159showcx(struct cmdtab const *cmd) 160{ 161 if (cmd->lauth & LOCAL_CX) 162 return "(c)"; 163 else if (cmd->lauth & LOCAL_CX_OPT) 164 return "(o)"; 165 166 return ""; 167} 168 169static int 170HelpCommand(struct cmdargs const *arg) 171{ 172 struct cmdtab const *cmd; 173 int n, cmax, dmax, cols, cxlen; 174 const char *cx; 175 176 if (!arg->prompt) { 177 log_Printf(LogWARN, "help: Cannot help without a prompt\n"); 178 return 0; 179 } 180 181 if (arg->argc > arg->argn) { 182 for (cmd = arg->cmdtab; cmd->name || cmd->alias; cmd++) 183 if ((cmd->lauth & arg->prompt->auth) && 184 ((cmd->name && !strcasecmp(cmd->name, arg->argv[arg->argn])) || 185 (cmd->alias && !strcasecmp(cmd->alias, arg->argv[arg->argn])))) { 186 prompt_Printf(arg->prompt, "%s %s\n", cmd->syntax, showcx(cmd)); 187 return 0; 188 } 189 return -1; 190 } 191 192 cmax = dmax = 0; 193 for (cmd = arg->cmdtab; cmd->func; cmd++) 194 if (cmd->name && (cmd->lauth & arg->prompt->auth)) { 195 if ((n = strlen(cmd->name) + strlen(showcx(cmd))) > cmax) 196 cmax = n; 197 if ((n = strlen(cmd->helpmes)) > dmax) 198 dmax = n; 199 } 200 201 cols = 80 / (dmax + cmax + 3); 202 n = 0; 203 prompt_Printf(arg->prompt, "(o) = Optional context," 204 " (c) = Context required\n"); 205 for (cmd = arg->cmdtab; cmd->func; cmd++) 206 if (cmd->name && (cmd->lauth & arg->prompt->auth)) { 207 cx = showcx(cmd); 208 cxlen = cmax - strlen(cmd->name); 209 if (n % cols != 0) 210 prompt_Printf(arg->prompt, " "); 211 prompt_Printf(arg->prompt, "%s%-*.*s: %-*.*s", 212 cmd->name, cxlen, cxlen, cx, dmax, dmax, cmd->helpmes); 213 if (++n % cols == 0) 214 prompt_Printf(arg->prompt, "\n"); 215 } 216 if (n % cols != 0) 217 prompt_Printf(arg->prompt, "\n"); 218 219 return 0; 220} 221 222static int 223CloneCommand(struct cmdargs const *arg) 224{ 225 char namelist[LINE_LEN]; 226 char *name; 227 int f; 228 229 if (arg->argc == arg->argn) 230 return -1; 231 232 namelist[sizeof namelist - 1] = '\0'; 233 for (f = arg->argn; f < arg->argc; f++) { 234 strncpy(namelist, arg->argv[f], sizeof namelist - 1); 235 for(name = strtok(namelist, ", "); name; name = strtok(NULL,", ")) 236 bundle_DatalinkClone(arg->bundle, arg->cx, name); 237 } 238 239 return 0; 240} 241 242static int 243RemoveCommand(struct cmdargs const *arg) 244{ 245 if (arg->argc != arg->argn) 246 return -1; 247 248 if (arg->cx->state != DATALINK_CLOSED) { 249 log_Printf(LogWARN, "remove: Cannot delete links that aren't closed\n"); 250 return 2; 251 } 252 253 bundle_DatalinkRemove(arg->bundle, arg->cx); 254 return 0; 255} 256 257static int 258RenameCommand(struct cmdargs const *arg) 259{ 260 if (arg->argc != arg->argn + 1) 261 return -1; 262 263 if (bundle_RenameDatalink(arg->bundle, arg->cx, arg->argv[arg->argn])) 264 return 0; 265 266 log_Printf(LogWARN, "%s -> %s: target name already exists\n", 267 arg->cx->name, arg->argv[arg->argn]); 268 return 1; 269} 270 271int 272LoadCommand(struct cmdargs const *arg) 273{ 274 const char *name; 275 276 if (arg->argc > arg->argn) 277 name = arg->argv[arg->argn]; 278 else 279 name = "default"; 280 281 if (!system_IsValid(name, arg->prompt, arg->bundle->phys_type.all)) { 282 log_Printf(LogWARN, "%s: Label not allowed\n", name); 283 return 1; 284 } else { 285 /* 286 * Set the label before & after so that `set enddisc' works and 287 * we handle nested `load' commands. 288 */ 289 bundle_SetLabel(arg->bundle, arg->argc > arg->argn ? name : NULL); 290 if (system_Select(arg->bundle, name, CONFFILE, arg->prompt, arg->cx) < 0) { 291 bundle_SetLabel(arg->bundle, NULL); 292 log_Printf(LogWARN, "%s: label not found.\n", name); 293 return -1; 294 } 295 bundle_SetLabel(arg->bundle, arg->argc > arg->argn ? name : NULL); 296 } 297 return 0; 298} 299 300int 301SaveCommand(struct cmdargs const *arg) 302{ 303 log_Printf(LogWARN, "save command is not implemented (yet).\n"); 304 return 1; 305} 306 307static int 308DialCommand(struct cmdargs const *arg) 309{ 310 int res; 311 312 if ((arg->cx && !(arg->cx->physical->type & (PHYS_INTERACTIVE|PHYS_AUTO))) 313 || (!arg->cx && 314 (arg->bundle->phys_type.all & ~(PHYS_INTERACTIVE|PHYS_AUTO)))) { 315 log_Printf(LogWARN, "Manual dial is only available for auto and" 316 " interactive links\n"); 317 return 1; 318 } 319 320 if (arg->argc > arg->argn && (res = LoadCommand(arg)) != 0) 321 return res; 322 323 bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1); 324 325 return 0; 326} 327 328#define isinword(ch) (isalnum(ch) || (ch) == '_') 329 330static char * 331strstrword(char *big, const char *little) 332{ 333 /* Get the first occurance of the word ``little'' in ``big'' */ 334 char *pos; 335 int len; 336 337 pos = big; 338 len = strlen(little); 339 340 while ((pos = strstr(pos, little)) != NULL) 341 if ((pos == big || !isinword(pos[-1])) && !isinword(pos[len])) 342 break; 343 else 344 pos++; 345 346 return pos; 347} 348 349static char * 350subst(char *tgt, const char *oldstr, const char *newstr) 351{ 352 /* tgt is a malloc()d area... realloc() as necessary */ 353 char *word, *ntgt; 354 int ltgt, loldstr, lnewstr, pos; 355 356 if ((word = strstrword(tgt, oldstr)) == NULL) 357 return tgt; 358 359 ltgt = strlen(tgt) + 1; 360 loldstr = strlen(oldstr); 361 lnewstr = strlen(newstr); 362 do { 363 pos = word - tgt; 364 if (loldstr > lnewstr) 365 bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr); 366 if (loldstr != lnewstr) { 367 ntgt = realloc(tgt, ltgt += lnewstr - loldstr); 368 if (ntgt == NULL) 369 break; /* Oh wonderful ! */ 370 word = ntgt + pos; 371 tgt = ntgt; 372 } 373 if (lnewstr > loldstr) 374 bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr); 375 bcopy(newstr, word, lnewstr); 376 } while ((word = strstrword(word, oldstr))); 377 378 return tgt; 379} 380 381static void 382expand(char **nargv, int argc, char const *const *oargv, struct bundle *bundle) 383{ 384 int arg; 385 386 nargv[0] = strdup(oargv[0]); 387 for (arg = 1; arg < argc; arg++) { 388 nargv[arg] = strdup(oargv[arg]); 389 nargv[arg] = subst(nargv[arg], "HISADDR", 390 inet_ntoa(bundle->ncp.ipcp.peer_ip)); 391 nargv[arg] = subst(nargv[arg], "AUTHNAME", bundle->cfg.auth.name); 392 nargv[arg] = subst(nargv[arg], "INTERFACE", bundle->iface->name); 393 nargv[arg] = subst(nargv[arg], "MYADDR", inet_ntoa(bundle->ncp.ipcp.my_ip)); 394 nargv[arg] = subst(nargv[arg], "USER", bundle->ncp.mp.peer.authname); 395 nargv[arg] = subst(nargv[arg], "PEER_ENDDISC", 396 mp_Enddisc(bundle->ncp.mp.peer.enddisc.class, 397 bundle->ncp.mp.peer.enddisc.address, 398 bundle->ncp.mp.peer.enddisc.len)); 399 nargv[arg] = subst(nargv[arg], "ENDDISC", 400 mp_Enddisc(bundle->ncp.mp.cfg.enddisc.class, 401 bundle->ncp.mp.cfg.enddisc.address, 402 bundle->ncp.mp.cfg.enddisc.len)); 403 nargv[arg] = subst(nargv[arg], "LABEL", bundle_GetLabel(bundle)); 404 } 405 nargv[arg] = NULL; 406} 407 408static int 409ShellCommand(struct cmdargs const *arg, int bg) 410{ 411 const char *shell; 412 pid_t shpid; 413 414#ifdef SHELL_ONLY_INTERACTIVELY 415 /* we're only allowed to shell when we run ppp interactively */ 416 if (arg->prompt && arg->prompt->owner) { 417 log_Printf(LogWARN, "Can't start a shell from a network connection\n"); 418 return 1; 419 } 420#endif 421 422 if (arg->argc == arg->argn) { 423 if (!arg->prompt) { 424 log_Printf(LogWARN, "Can't start an interactive shell from" 425 " a config file\n"); 426 return 1; 427 } else if (arg->prompt->owner) { 428 log_Printf(LogWARN, "Can't start an interactive shell from" 429 " a socket connection\n"); 430 return 1; 431 } else if (bg) { 432 log_Printf(LogWARN, "Can only start an interactive shell in" 433 " the foreground mode\n"); 434 return 1; 435 } 436 } 437 438 if ((shpid = fork()) == 0) { 439 int i, fd; 440 441 if ((shell = getenv("SHELL")) == 0) 442 shell = _PATH_BSHELL; 443 444 timer_TermService(); 445 446 if (arg->prompt) 447 fd = arg->prompt->fd_out; 448 else if ((fd = open(_PATH_DEVNULL, O_RDWR)) == -1) { 449 log_Printf(LogALERT, "Failed to open %s: %s\n", 450 _PATH_DEVNULL, strerror(errno)); 451 exit(1); 452 } 453 for (i = 0; i < 3; i++) 454 dup2(fd, i); 455 456 fcntl(3, F_SETFD, 1); /* Set close-on-exec flag */ 457 458 setuid(geteuid()); 459 if (arg->argc > arg->argn) { 460 /* substitute pseudo args */ 461 char *argv[MAXARGS]; 462 int argc = arg->argc - arg->argn; 463 464 if (argc >= sizeof argv / sizeof argv[0]) { 465 argc = sizeof argv / sizeof argv[0] - 1; 466 log_Printf(LogWARN, "Truncating shell command to %d args\n", argc); 467 } 468 expand(argv, argc, arg->argv + arg->argn, arg->bundle); 469 if (bg) { 470 pid_t p; 471 472 p = getpid(); 473 if (daemon(1, 1) == -1) { 474 log_Printf(LogERROR, "%d: daemon: %s\n", (int)p, strerror(errno)); 475 exit(1); 476 } 477 } else if (arg->prompt) 478 printf("ppp: Pausing until %s finishes\n", arg->argv[arg->argn]); 479 execvp(argv[0], argv); 480 } else { 481 if (arg->prompt) 482 printf("ppp: Pausing until %s finishes\n", shell); 483 prompt_TtyOldMode(arg->prompt); 484 execl(shell, shell, NULL); 485 } 486 487 log_Printf(LogWARN, "exec() of %s failed\n", 488 arg->argc > arg->argn ? arg->argv[arg->argn] : shell); 489 exit(255); 490 } 491 492 if (shpid == (pid_t) - 1) 493 log_Printf(LogERROR, "Fork failed: %s\n", strerror(errno)); 494 else { 495 int status; 496 waitpid(shpid, &status, 0); 497 } 498 499 if (arg->prompt && !arg->prompt->owner) 500 prompt_TtyCommandMode(arg->prompt); 501 502 return 0; 503} 504 505static int 506BgShellCommand(struct cmdargs const *arg) 507{ 508 if (arg->argc == arg->argn) 509 return -1; 510 return ShellCommand(arg, 1); 511} 512 513static int 514FgShellCommand(struct cmdargs const *arg) 515{ 516 return ShellCommand(arg, 0); 517} 518 519#ifndef NOALIAS 520static struct cmdtab const AliasCommands[] = 521{ 522 {"addr", NULL, alias_RedirectAddr, LOCAL_AUTH, 523 "static address translation", "alias addr [addr_local addr_alias]"}, 524 {"deny_incoming", NULL, AliasOption, LOCAL_AUTH, 525 "stop incoming connections", "alias deny_incoming [yes|no]", 526 (const void *) PKT_ALIAS_DENY_INCOMING}, 527 {"enable", NULL, AliasEnable, LOCAL_AUTH, 528 "enable IP aliasing", "alias enable [yes|no]"}, 529 {"log", NULL, AliasOption, LOCAL_AUTH, 530 "log aliasing link creation", "alias log [yes|no]", 531 (const void *) PKT_ALIAS_LOG}, 532 {"port", NULL, alias_RedirectPort, LOCAL_AUTH, 533 "port redirection", "alias port [proto addr_local:port_local port_alias]"}, 534 {"same_ports", NULL, AliasOption, LOCAL_AUTH, 535 "try to leave port numbers unchanged", "alias same_ports [yes|no]", 536 (const void *) PKT_ALIAS_SAME_PORTS}, 537 {"unregistered_only", NULL, AliasOption, LOCAL_AUTH, 538 "alias unregistered (private) IP address space only", 539 "alias unregistered_only [yes|no]", 540 (const void *) PKT_ALIAS_UNREGISTERED_ONLY}, 541 {"use_sockets", NULL, AliasOption, LOCAL_AUTH, 542 "allocate host sockets", "alias use_sockets [yes|no]", 543 (const void *) PKT_ALIAS_USE_SOCKETS}, 544 {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, 545 "Display this message", "alias help|? [command]", AliasCommands}, 546 {NULL, NULL, NULL}, 547}; 548#endif 549 550static struct cmdtab const AllowCommands[] = { 551 {"modes", "mode", AllowModes, LOCAL_AUTH, 552 "Only allow certain ppp modes", "allow modes mode..."}, 553 {"users", "user", AllowUsers, LOCAL_AUTH, 554 "Only allow ppp access to certain users", "allow users logname..."}, 555 {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, 556 "Display this message", "allow help|? [command]", AllowCommands}, 557 {NULL, NULL, NULL}, 558}; 559 560static struct cmdtab const IfaceCommands[] = 561{ 562 {"add", NULL, IfaceAddCommand, LOCAL_AUTH, 563 "Add iface address", "iface add addr[/bits| mask] peer", NULL}, 564 {NULL, "add!", IfaceAddCommand, LOCAL_AUTH, 565 "Add or change an iface address", "iface add! addr[/bits| mask] peer", 566 (void *)1}, 567 {"clear", NULL, IfaceClearCommand, LOCAL_AUTH, 568 "Clear iface address(es)", "iface clear"}, 569 {"delete", "rm", IfaceDeleteCommand, LOCAL_AUTH, 570 "Delete iface address", "iface delete addr", NULL}, 571 {NULL, "rm!", IfaceDeleteCommand, LOCAL_AUTH, 572 "Delete iface address", "iface delete addr", (void *)1}, 573 {NULL, "delete!", IfaceDeleteCommand, LOCAL_AUTH, 574 "Delete iface address", "iface delete addr", (void *)1}, 575 {"show", NULL, iface_Show, LOCAL_AUTH, 576 "Show iface address(es)", "iface show"}, 577 {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, 578 "Display this message", "alias help|? [command]", IfaceCommands}, 579 {NULL, NULL, NULL}, 580}; 581 582static struct cmdtab const Commands[] = { 583 {"accept", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT, 584 "accept option request", "accept option .."}, 585 {"add", NULL, AddCommand, LOCAL_AUTH, 586 "add route", "add dest mask gateway", NULL}, 587 {NULL, "add!", AddCommand, LOCAL_AUTH, 588 "add or change route", "add! dest mask gateway", (void *)1}, 589#ifndef NOALIAS 590 {"alias", NULL, RunListCommand, LOCAL_AUTH, 591 "alias control", "alias option [yes|no]", AliasCommands}, 592#endif 593 {"allow", "auth", RunListCommand, LOCAL_AUTH, 594 "Allow ppp access", "allow users|modes ....", AllowCommands}, 595 {"bg", "!bg", BgShellCommand, LOCAL_AUTH, 596 "Run a background command", "[!]bg command"}, 597 {"clear", NULL, ClearCommand, LOCAL_AUTH | LOCAL_CX_OPT, 598 "Clear throughput statistics", "clear ipcp|modem [current|overall|peak]..."}, 599 {"clone", NULL, CloneCommand, LOCAL_AUTH | LOCAL_CX, 600 "Clone a link", "clone newname..."}, 601 {"close", NULL, CloseCommand, LOCAL_AUTH | LOCAL_CX_OPT, 602 "Close an FSM", "close [lcp|ccp]"}, 603 {"delete", NULL, DeleteCommand, LOCAL_AUTH, 604 "delete route", "delete dest", NULL}, 605 {NULL, "delete!", DeleteCommand, LOCAL_AUTH, 606 "delete a route if it exists", "delete! dest", (void *)1}, 607 {"deny", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT, 608 "Deny option request", "deny option .."}, 609 {"dial", "call", DialCommand, LOCAL_AUTH | LOCAL_CX_OPT, 610 "Dial and login", "dial|call [remote]", NULL}, 611 {"disable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT, 612 "Disable option", "disable option .."}, 613 {"down", NULL, DownCommand, LOCAL_AUTH | LOCAL_CX_OPT, 614 "Generate a down event", "down"}, 615 {"enable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT, 616 "Enable option", "enable option .."}, 617 {"iface", "interface", RunListCommand, LOCAL_AUTH, 618 "interface control", "iface option ...", IfaceCommands}, 619 {"link", "datalink", LinkCommand, LOCAL_AUTH, 620 "Link specific commands", "link name command ..."}, 621 {"load", NULL, LoadCommand, LOCAL_AUTH | LOCAL_CX_OPT, 622 "Load settings", "load [remote]"}, 623 {"open", NULL, OpenCommand, LOCAL_AUTH | LOCAL_CX_OPT, 624 "Open an FSM", "open! [lcp|ccp|ipcp]", (void *)1}, 625 {"passwd", NULL, PasswdCommand, LOCAL_NO_AUTH, 626 "Password for manipulation", "passwd LocalPassword"}, 627 {"quit", "bye", QuitCommand, LOCAL_AUTH | LOCAL_NO_AUTH, 628 "Quit PPP program", "quit|bye [all]"}, 629 {"remove", "rm", RemoveCommand, LOCAL_AUTH | LOCAL_CX, 630 "Remove a link", "remove"}, 631 {"rename", "mv", RenameCommand, LOCAL_AUTH | LOCAL_CX, 632 "Rename a link", "rename name"}, 633 {"save", NULL, SaveCommand, LOCAL_AUTH, 634 "Save settings", "save"}, 635 {"set", "setup", SetCommand, LOCAL_AUTH | LOCAL_CX_OPT, 636 "Set parameters", "set[up] var value"}, 637 {"shell", "!", FgShellCommand, LOCAL_AUTH, 638 "Run a subshell", "shell|! [sh command]"}, 639 {"show", NULL, ShowCommand, LOCAL_AUTH | LOCAL_CX_OPT, 640 "Show status and stats", "show var"}, 641 {"term", NULL, TerminalCommand, LOCAL_AUTH | LOCAL_CX, 642 "Enter terminal mode", "term"}, 643 {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, 644 "Display this message", "help|? [command]", Commands}, 645 {NULL, NULL, NULL}, 646}; 647 648static int 649ShowEscape(struct cmdargs const *arg) 650{ 651 if (arg->cx->physical->async.cfg.EscMap[32]) { 652 int code, bit; 653 const char *sep = ""; 654 655 for (code = 0; code < 32; code++) 656 if (arg->cx->physical->async.cfg.EscMap[code]) 657 for (bit = 0; bit < 8; bit++) 658 if (arg->cx->physical->async.cfg.EscMap[code] & (1 << bit)) { 659 prompt_Printf(arg->prompt, "%s0x%02x", sep, (code << 3) + bit); 660 sep = ", "; 661 } 662 prompt_Printf(arg->prompt, "\n"); 663 } 664 return 0; 665} 666 667static int 668ShowTimerList(struct cmdargs const *arg) 669{ 670 timer_Show(0, arg->prompt); 671 return 0; 672} 673 674static int 675ShowStopped(struct cmdargs const *arg) 676{ 677 prompt_Printf(arg->prompt, " Stopped Timer: LCP: "); 678 if (!arg->cx->physical->link.lcp.fsm.StoppedTimer.load) 679 prompt_Printf(arg->prompt, "Disabled"); 680 else 681 prompt_Printf(arg->prompt, "%ld secs", 682 arg->cx->physical->link.lcp.fsm.StoppedTimer.load / SECTICKS); 683 684 prompt_Printf(arg->prompt, ", CCP: "); 685 if (!arg->cx->physical->link.ccp.fsm.StoppedTimer.load) 686 prompt_Printf(arg->prompt, "Disabled"); 687 else 688 prompt_Printf(arg->prompt, "%ld secs", 689 arg->cx->physical->link.ccp.fsm.StoppedTimer.load / SECTICKS); 690 691 prompt_Printf(arg->prompt, "\n"); 692 693 return 0; 694} 695 696static int 697ShowVersion(struct cmdargs const *arg) 698{ 699 prompt_Printf(arg->prompt, "PPP Version %s - %s\n", Version, VersionDate); 700 return 0; 701} 702 703static int 704ShowProtocolStats(struct cmdargs const *arg) 705{ 706 struct link *l = command_ChooseLink(arg); 707 708 prompt_Printf(arg->prompt, "%s:\n", l->name); 709 link_ReportProtocolStatus(l, arg->prompt); 710 return 0; 711} 712 713static struct cmdtab const ShowCommands[] = { 714 {"bundle", NULL, bundle_ShowStatus, LOCAL_AUTH, 715 "bundle details", "show bundle"}, 716 {"ccp", NULL, ccp_ReportStatus, LOCAL_AUTH | LOCAL_CX_OPT, 717 "CCP status", "show cpp"}, 718 {"compress", NULL, sl_Show, LOCAL_AUTH, 719 "VJ compression stats", "show compress"}, 720 {"escape", NULL, ShowEscape, LOCAL_AUTH | LOCAL_CX, 721 "escape characters", "show escape"}, 722 {"filter", NULL, filter_Show, LOCAL_AUTH, 723 "packet filters", "show filter [in|out|dial|alive]"}, 724 {"hdlc", NULL, hdlc_ReportStatus, LOCAL_AUTH | LOCAL_CX, 725 "HDLC errors", "show hdlc"}, 726 {"iface", "interface", iface_Show, LOCAL_AUTH, 727 "Interface status", "show iface"}, 728 {"ipcp", NULL, ipcp_Show, LOCAL_AUTH, 729 "IPCP status", "show ipcp"}, 730 {"lcp", NULL, lcp_ReportStatus, LOCAL_AUTH | LOCAL_CX, 731 "LCP status", "show lcp"}, 732 {"link", "datalink", datalink_Show, LOCAL_AUTH | LOCAL_CX, 733 "(high-level) link info", "show link"}, 734 {"links", NULL, bundle_ShowLinks, LOCAL_AUTH, 735 "available link names", "show links"}, 736 {"log", NULL, log_ShowLevel, LOCAL_AUTH, 737 "log levels", "show log"}, 738 {"mem", NULL, mbuf_Show, LOCAL_AUTH, 739 "mbuf allocations", "show mem"}, 740 {"modem", NULL, modem_ShowStatus, LOCAL_AUTH | LOCAL_CX, 741 "(low-level) link info", "show modem"}, 742 {"mp", "multilink", mp_ShowStatus, LOCAL_AUTH, 743 "multilink setup", "show mp"}, 744 {"proto", NULL, ShowProtocolStats, LOCAL_AUTH | LOCAL_CX_OPT, 745 "protocol summary", "show proto"}, 746 {"route", NULL, route_Show, LOCAL_AUTH, 747 "routing table", "show route"}, 748 {"stopped", NULL, ShowStopped, LOCAL_AUTH | LOCAL_CX, 749 "STOPPED timeout", "show stopped"}, 750 {"timers", NULL, ShowTimerList, LOCAL_AUTH, 751 "alarm timers", "show timers"}, 752 {"version", NULL, ShowVersion, LOCAL_NO_AUTH | LOCAL_AUTH, 753 "version string", "show version"}, 754 {"who", NULL, log_ShowWho, LOCAL_AUTH, 755 "client list", "show who"}, 756 {"help", "?", HelpCommand, LOCAL_NO_AUTH | LOCAL_AUTH, 757 "Display this message", "show help|? [command]", ShowCommands}, 758 {NULL, NULL, NULL}, 759}; 760 761static struct cmdtab const * 762FindCommand(struct cmdtab const *cmds, const char *str, int *pmatch) 763{ 764 int nmatch; 765 int len; 766 struct cmdtab const *found; 767 768 found = NULL; 769 len = strlen(str); 770 nmatch = 0; 771 while (cmds->func) { 772 if (cmds->name && strncasecmp(str, cmds->name, len) == 0) { 773 if (cmds->name[len] == '\0') { 774 *pmatch = 1; 775 return cmds; 776 } 777 nmatch++; 778 found = cmds; 779 } else if (cmds->alias && strncasecmp(str, cmds->alias, len) == 0) { 780 if (cmds->alias[len] == '\0') { 781 *pmatch = 1; 782 return cmds; 783 } 784 nmatch++; 785 found = cmds; 786 } 787 cmds++; 788 } 789 *pmatch = nmatch; 790 return found; 791} 792 793static const char * 794mkPrefix(int argc, char const *const *argv, char *tgt, int sz) 795{ 796 int f, tlen, len; 797 798 tlen = 0; 799 for (f = 0; f < argc && tlen < sz - 2; f++) { 800 if (f) 801 tgt[tlen++] = ' '; 802 len = strlen(argv[f]); 803 if (len > sz - tlen - 1) 804 len = sz - tlen - 1; 805 strncpy(tgt+tlen, argv[f], len); 806 tlen += len; 807 } 808 tgt[tlen] = '\0'; 809 return tgt; 810} 811 812static int 813FindExec(struct bundle *bundle, struct cmdtab const *cmds, int argc, int argn, 814 char const *const *argv, struct prompt *prompt, struct datalink *cx) 815{ 816 struct cmdtab const *cmd; 817 int val = 1; 818 int nmatch; 819 struct cmdargs arg; 820 char prefix[100]; 821 822 cmd = FindCommand(cmds, argv[argn], &nmatch); 823 if (nmatch > 1) 824 log_Printf(LogWARN, "%s: Ambiguous command\n", 825 mkPrefix(argn+1, argv, prefix, sizeof prefix)); 826 else if (cmd && (!prompt || (cmd->lauth & prompt->auth))) { 827 if ((cmd->lauth & LOCAL_CX) && !cx) 828 /* We've got no context, but we require it */ 829 cx = bundle2datalink(bundle, NULL); 830 831 if ((cmd->lauth & LOCAL_CX) && !cx) 832 log_Printf(LogWARN, "%s: No context (use the `link' command)\n", 833 mkPrefix(argn+1, argv, prefix, sizeof prefix)); 834 else { 835 if (cx && !(cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) { 836 log_Printf(LogWARN, "%s: Redundant context (%s) ignored\n", 837 mkPrefix(argn+1, argv, prefix, sizeof prefix), cx->name); 838 cx = NULL; 839 } 840 arg.cmdtab = cmds; 841 arg.cmd = cmd; 842 arg.argc = argc; 843 arg.argn = argn+1; 844 arg.argv = argv; 845 arg.bundle = bundle; 846 arg.cx = cx; 847 arg.prompt = prompt; 848 val = (*cmd->func) (&arg); 849 } 850 } else 851 log_Printf(LogWARN, "%s: Invalid command\n", 852 mkPrefix(argn+1, argv, prefix, sizeof prefix)); 853 854 if (val == -1) 855 log_Printf(LogWARN, "Usage: %s\n", cmd->syntax); 856 else if (val) 857 log_Printf(LogWARN, "%s: Failed %d\n", 858 mkPrefix(argn+1, argv, prefix, sizeof prefix), val); 859 860 return val; 861} 862 863int 864command_Interpret(char *buff, int nb, char *argv[MAXARGS]) 865{ 866 char *cp; 867 868 if (nb > 0) { 869 cp = buff + strcspn(buff, "\r\n"); 870 if (cp) 871 *cp = '\0'; 872 return MakeArgs(buff, argv, MAXARGS); 873 } 874 return 0; 875} 876 877static int 878arghidden(int argc, char const *const *argv, int n) 879{ 880 /* Is arg n of the given command to be hidden from the log ? */ 881 882 /* set authkey xxxxx */ 883 /* set key xxxxx */ 884 if (n == 2 && !strncasecmp(argv[0], "se", 2) && 885 (!strncasecmp(argv[1], "authk", 5) || !strncasecmp(argv[1], "ke", 2))) 886 return 1; 887 888 /* passwd xxxxx */ 889 if (n == 1 && !strncasecmp(argv[0], "p", 1)) 890 return 1; 891 892 /* set server port xxxxx .... */ 893 if (n == 3 && !strncasecmp(argv[0], "se", 2) && 894 !strncasecmp(argv[1], "se", 2)) 895 return 1; 896 897 return 0; 898} 899 900void 901command_Run(struct bundle *bundle, int argc, char const *const *argv, 902 struct prompt *prompt, const char *label, struct datalink *cx) 903{ 904 if (argc > 0) { 905 if (log_IsKept(LogCOMMAND)) { 906 static char buf[LINE_LEN]; 907 int f, n; 908 909 *buf = '\0'; 910 if (label) { 911 strncpy(buf, label, sizeof buf - 3); 912 buf[sizeof buf - 3] = '\0'; 913 strcat(buf, ": "); 914 } 915 n = strlen(buf); 916 for (f = 0; f < argc; f++) { 917 if (n < sizeof buf - 1 && f) 918 buf[n++] = ' '; 919 if (arghidden(argc, argv, f)) 920 strncpy(buf+n, "********", sizeof buf - n - 1); 921 else 922 strncpy(buf+n, argv[f], sizeof buf - n - 1); 923 n += strlen(buf+n); 924 } 925 log_Printf(LogCOMMAND, "%s\n", buf); 926 } 927 FindExec(bundle, Commands, argc, 0, argv, prompt, cx); 928 } 929} 930 931void 932command_Decode(struct bundle *bundle, char *buff, int nb, struct prompt *prompt, 933 const char *label) 934{ 935 int argc; 936 char *argv[MAXARGS]; 937 938 argc = command_Interpret(buff, nb, argv); 939 command_Run(bundle, argc, (char const *const *)argv, prompt, label, NULL); 940} 941 942static int 943ShowCommand(struct cmdargs const *arg) 944{ 945 if (!arg->prompt) 946 log_Printf(LogWARN, "show: Cannot show without a prompt\n"); 947 else if (arg->argc > arg->argn) 948 FindExec(arg->bundle, ShowCommands, arg->argc, arg->argn, arg->argv, 949 arg->prompt, arg->cx); 950 else 951 prompt_Printf(arg->prompt, "Use ``show ?'' to get a list.\n"); 952 953 return 0; 954} 955 956static int 957TerminalCommand(struct cmdargs const *arg) 958{ 959 if (!arg->prompt) { 960 log_Printf(LogWARN, "term: Need a prompt\n"); 961 return 1; 962 } 963 964 if (arg->cx->physical->link.lcp.fsm.state > ST_CLOSED) { 965 prompt_Printf(arg->prompt, "LCP state is [%s]\n", 966 State2Nam(arg->cx->physical->link.lcp.fsm.state)); 967 return 1; 968 } 969 970 datalink_Up(arg->cx, 0, 0); 971 prompt_TtyTermMode(arg->prompt, arg->cx); 972 return 0; 973} 974 975static int 976QuitCommand(struct cmdargs const *arg) 977{ 978 if (!arg->prompt || prompt_IsController(arg->prompt) || 979 (arg->argc > arg->argn && !strcasecmp(arg->argv[arg->argn], "all") && 980 (arg->prompt->auth & LOCAL_AUTH))) 981 Cleanup(EX_NORMAL); 982 if (arg->prompt) 983 prompt_Destroy(arg->prompt, 1); 984 985 return 0; 986} 987 988static int 989OpenCommand(struct cmdargs const *arg) 990{ 991 if (arg->argc == arg->argn) 992 bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1); 993 else if (arg->argc == arg->argn + 1) { 994 if (!strcasecmp(arg->argv[arg->argn], "lcp")) { 995 struct datalink *cx = arg->cx ? 996 arg->cx : bundle2datalink(arg->bundle, NULL); 997 if (cx) { 998 if (cx->physical->link.lcp.fsm.state == ST_OPENED) 999 fsm_Reopen(&cx->physical->link.lcp.fsm); 1000 else 1001 bundle_Open(arg->bundle, cx->name, PHYS_ALL, 1); 1002 } else 1003 log_Printf(LogWARN, "open lcp: You must specify a link\n"); 1004 } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) { 1005 struct fsm *fp; 1006 1007 fp = &command_ChooseLink(arg)->ccp.fsm; 1008 if (fp->link->lcp.fsm.state != ST_OPENED) 1009 log_Printf(LogWARN, "open: LCP must be open before opening CCP\n"); 1010 else if (fp->state == ST_OPENED) 1011 fsm_Reopen(fp); 1012 else { 1013 fp->open_mode = 0; /* Not passive any more */ 1014 if (fp->state == ST_STOPPED) { 1015 fsm_Down(fp); 1016 fsm_Up(fp); 1017 } else { 1018 fsm_Up(fp); 1019 fsm_Open(fp); 1020 } 1021 } 1022 } else if (!strcasecmp(arg->argv[arg->argn], "ipcp")) { 1023 if (arg->cx) 1024 log_Printf(LogWARN, "open ipcp: You need not specify a link\n"); 1025 if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED) 1026 fsm_Reopen(&arg->bundle->ncp.ipcp.fsm); 1027 else 1028 bundle_Open(arg->bundle, NULL, PHYS_ALL, 1); 1029 } else 1030 return -1; 1031 } else 1032 return -1; 1033 1034 return 0; 1035} 1036 1037static int 1038CloseCommand(struct cmdargs const *arg) 1039{ 1040 if (arg->argc == arg->argn) 1041 bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_STAYDOWN); 1042 else if (arg->argc == arg->argn + 1) { 1043 if (!strcasecmp(arg->argv[arg->argn], "lcp")) 1044 bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_LCP); 1045 else if (!strcasecmp(arg->argv[arg->argn], "ccp") || 1046 !strcasecmp(arg->argv[arg->argn], "ccp!")) { 1047 struct fsm *fp; 1048 1049 fp = &command_ChooseLink(arg)->ccp.fsm; 1050 if (fp->state == ST_OPENED) { 1051 fsm_Close(fp); 1052 if (arg->argv[arg->argn][3] == '!') 1053 fp->open_mode = 0; /* Stay ST_CLOSED */ 1054 else 1055 fp->open_mode = OPEN_PASSIVE; /* Wait for the peer to start */ 1056 } 1057 } else 1058 return -1; 1059 } else 1060 return -1; 1061 1062 return 0; 1063} 1064 1065static int 1066DownCommand(struct cmdargs const *arg) 1067{ 1068 if (arg->argc == arg->argn) { 1069 if (arg->cx) 1070 datalink_Down(arg->cx, CLOSE_STAYDOWN); 1071 else 1072 bundle_Down(arg->bundle, CLOSE_STAYDOWN); 1073 } else if (arg->argc == arg->argn + 1) { 1074 if (!strcasecmp(arg->argv[arg->argn], "lcp")) { 1075 if (arg->cx) 1076 datalink_Down(arg->cx, CLOSE_LCP); 1077 else 1078 bundle_Down(arg->bundle, CLOSE_LCP); 1079 } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) { 1080 struct fsm *fp = arg->cx ? &arg->cx->physical->link.ccp.fsm : 1081 &arg->bundle->ncp.mp.link.ccp.fsm; 1082 fsm2initial(fp); 1083 } else 1084 return -1; 1085 } else 1086 return -1; 1087 1088 return 0; 1089} 1090 1091static int 1092SetModemSpeed(struct cmdargs const *arg) 1093{ 1094 long speed; 1095 char *end; 1096 1097 if (arg->argc > arg->argn && *arg->argv[arg->argn]) { 1098 if (arg->argc > arg->argn+1) { 1099 log_Printf(LogWARN, "SetModemSpeed: Too many arguments"); 1100 return -1; 1101 } 1102 if (strcasecmp(arg->argv[arg->argn], "sync") == 0) { 1103 physical_SetSync(arg->cx->physical); 1104 return 0; 1105 } 1106 end = NULL; 1107 speed = strtol(arg->argv[arg->argn], &end, 10); 1108 if (*end) { 1109 log_Printf(LogWARN, "SetModemSpeed: Bad argument \"%s\"", 1110 arg->argv[arg->argn]); 1111 return -1; 1112 } 1113 if (physical_SetSpeed(arg->cx->physical, speed)) 1114 return 0; 1115 log_Printf(LogWARN, "%s: Invalid speed\n", arg->argv[arg->argn]); 1116 } else 1117 log_Printf(LogWARN, "SetModemSpeed: No speed specified\n"); 1118 1119 return -1; 1120} 1121 1122static int 1123SetStoppedTimeout(struct cmdargs const *arg) 1124{ 1125 struct link *l = &arg->cx->physical->link; 1126 1127 l->lcp.fsm.StoppedTimer.load = 0; 1128 l->ccp.fsm.StoppedTimer.load = 0; 1129 if (arg->argc <= arg->argn+2) { 1130 if (arg->argc > arg->argn) { 1131 l->lcp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn]) * SECTICKS; 1132 if (arg->argc > arg->argn+1) 1133 l->ccp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn+1]) * SECTICKS; 1134 } 1135 return 0; 1136 } 1137 return -1; 1138} 1139 1140#define ismask(x) \ 1141 (*x == '0' && strlen(x) == 4 && strspn(x+1, "0123456789.") == 3) 1142 1143static int 1144SetServer(struct cmdargs const *arg) 1145{ 1146 int res = -1; 1147 1148 if (arg->argc > arg->argn && arg->argc < arg->argn+4) { 1149 const char *port, *passwd, *mask; 1150 1151 /* What's what ? */ 1152 port = arg->argv[arg->argn]; 1153 if (arg->argc == arg->argn + 2) { 1154 passwd = arg->argv[arg->argn+1]; 1155 mask = NULL; 1156 } else if (arg->argc == arg->argn + 3) { 1157 passwd = arg->argv[arg->argn+1]; 1158 mask = arg->argv[arg->argn+2]; 1159 if (!ismask(mask)) 1160 return -1; 1161 } else if (strcasecmp(port, "none") == 0) { 1162 if (server_Close(arg->bundle)) 1163 log_Printf(LogPHASE, "Disabled server port.\n"); 1164 return 0; 1165 } else 1166 return -1; 1167 1168 strncpy(server.passwd, passwd, sizeof server.passwd - 1); 1169 server.passwd[sizeof server.passwd - 1] = '\0'; 1170 1171 if (*port == '/') { 1172 mode_t imask; 1173 char *ptr, name[LINE_LEN + 12]; 1174 1175 if (mask != NULL) { 1176 unsigned m; 1177 1178 if (sscanf(mask, "%o", &m) == 1) 1179 imask = m; 1180 else 1181 return -1; 1182 } else 1183 imask = (mode_t)-1; 1184 1185 ptr = strstr(port, "%d"); 1186 if (ptr) { 1187 snprintf(name, sizeof name, "%.*s%d%s", 1188 (int)(ptr - port), port, arg->bundle->unit, ptr + 2); 1189 port = name; 1190 } 1191 res = server_LocalOpen(arg->bundle, port, imask); 1192 } else { 1193 int iport, add = 0; 1194 1195 if (mask != NULL) 1196 return -1; 1197 1198 if (*port == '+') { 1199 port++; 1200 add = 1; 1201 } 1202 if (strspn(port, "0123456789") != strlen(port)) { 1203 struct servent *s; 1204 1205 if ((s = getservbyname(port, "tcp")) == NULL) { 1206 iport = 0; 1207 log_Printf(LogWARN, "%s: Invalid port or service\n", port); 1208 } else 1209 iport = ntohs(s->s_port); 1210 } else 1211 iport = atoi(port); 1212 1213 if (iport) { 1214 if (add) 1215 iport += arg->bundle->unit; 1216 res = server_TcpOpen(arg->bundle, iport); 1217 } else 1218 res = -1; 1219 } 1220 } 1221 1222 return res; 1223} 1224 1225static int 1226SetModemParity(struct cmdargs const *arg) 1227{ 1228 return arg->argc > arg->argn ? modem_SetParity(arg->cx->physical, 1229 arg->argv[arg->argn]) : -1; 1230} 1231 1232static int 1233SetEscape(struct cmdargs const *arg) 1234{ 1235 int code; 1236 int argc = arg->argc - arg->argn; 1237 char const *const *argv = arg->argv + arg->argn; 1238 1239 for (code = 0; code < 33; code++) 1240 arg->cx->physical->async.cfg.EscMap[code] = 0; 1241 1242 while (argc-- > 0) { 1243 sscanf(*argv++, "%x", &code); 1244 code &= 0xff; 1245 arg->cx->physical->async.cfg.EscMap[code >> 3] |= (1 << (code & 7)); 1246 arg->cx->physical->async.cfg.EscMap[32] = 1; 1247 } 1248 return 0; 1249} 1250 1251static struct in_addr 1252GetIpAddr(const char *cp) 1253{ 1254 struct hostent *hp; 1255 struct in_addr ipaddr; 1256 1257 if (inet_aton(cp, &ipaddr) == 0) { 1258 hp = gethostbyname(cp); 1259 if (hp && hp->h_addrtype == AF_INET) 1260 memcpy(&ipaddr, hp->h_addr, hp->h_length); 1261 else 1262 ipaddr.s_addr = 0; 1263 } 1264 return (ipaddr); 1265} 1266 1267static int 1268SetInterfaceAddr(struct cmdargs const *arg) 1269{ 1270 struct ipcp *ipcp = &arg->bundle->ncp.ipcp; 1271 const char *hisaddr; 1272 1273 if (arg->argc > arg->argn + 4) 1274 return -1; 1275 1276 hisaddr = NULL; 1277 ipcp->cfg.my_range.ipaddr.s_addr = INADDR_ANY; 1278 ipcp->cfg.peer_range.ipaddr.s_addr = INADDR_ANY; 1279 ipcp->cfg.HaveTriggerAddress = 0; 1280 ipcp->cfg.netmask.s_addr = INADDR_ANY; 1281 iplist_reset(&ipcp->cfg.peer_list); 1282 1283 if (arg->argc > arg->argn) { 1284 if (!ParseAddr(ipcp, arg->argc - arg->argn, arg->argv + arg->argn, 1285 &ipcp->cfg.my_range.ipaddr, &ipcp->cfg.my_range.mask, 1286 &ipcp->cfg.my_range.width)) 1287 return 1; 1288 if (arg->argc > arg->argn+1) { 1289 hisaddr = arg->argv[arg->argn+1]; 1290 if (arg->argc > arg->argn+2) { 1291 ipcp->cfg.netmask = GetIpAddr(arg->argv[arg->argn+2]); 1292 if (arg->argc > arg->argn+3) { 1293 ipcp->cfg.TriggerAddress = GetIpAddr(arg->argv[arg->argn+3]); 1294 ipcp->cfg.HaveTriggerAddress = 1; 1295 } 1296 } 1297 } 1298 } 1299 1300 /* 0.0.0.0 means any address (0 bits) */ 1301 if (ipcp->cfg.my_range.ipaddr.s_addr == INADDR_ANY) { 1302 ipcp->cfg.my_range.mask.s_addr = INADDR_ANY; 1303 ipcp->cfg.my_range.width = 0; 1304 } 1305 ipcp->my_ip.s_addr = ipcp->cfg.my_range.ipaddr.s_addr; 1306 1307 if (hisaddr && !ipcp_UseHisaddr(arg->bundle, hisaddr, 1308 arg->bundle->phys_type.all & PHYS_AUTO)) 1309 return 4; 1310 1311 return 0; 1312} 1313 1314static int 1315SetVariable(struct cmdargs const *arg) 1316{ 1317 long long_val, param = (long)arg->cmd->args; 1318 int mode, dummyint; 1319 const char *argp; 1320 struct datalink *cx = arg->cx; /* LOCAL_CX uses this */ 1321 const char *err = NULL; 1322 struct link *l = command_ChooseLink(arg); /* LOCAL_CX_OPT uses this */ 1323 struct in_addr dummyaddr, *addr; 1324 1325 if (arg->argc > arg->argn) 1326 argp = arg->argv[arg->argn]; 1327 else 1328 argp = ""; 1329 1330 if ((arg->cmd->lauth & LOCAL_CX) && !cx) { 1331 log_Printf(LogWARN, "set %s: No context (use the `link' command)\n", 1332 arg->cmd->name); 1333 return 1; 1334 } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) { 1335 log_Printf(LogWARN, "set %s: Redundant context (%s) ignored\n", 1336 arg->cmd->name, cx->name); 1337 cx = NULL; 1338 } 1339 1340 switch (param) { 1341 case VAR_AUTHKEY: 1342 switch (bundle_Phase(arg->bundle)) { 1343 case PHASE_DEAD: 1344 case PHASE_ESTABLISH: 1345 strncpy(arg->bundle->cfg.auth.key, argp, 1346 sizeof arg->bundle->cfg.auth.key - 1); 1347 arg->bundle->cfg.auth.key[sizeof arg->bundle->cfg.auth.key - 1] = '\0'; 1348 break; 1349 default: 1350 err = "set authkey: Only available at phase DEAD/ESTABLISH\n"; 1351 log_Printf(LogWARN, err); 1352 break; 1353 } 1354 break; 1355 1356 case VAR_AUTHNAME: 1357 switch (bundle_Phase(arg->bundle)) { 1358 case PHASE_DEAD: 1359 case PHASE_ESTABLISH: 1360 strncpy(arg->bundle->cfg.auth.name, argp, 1361 sizeof arg->bundle->cfg.auth.name - 1); 1362 arg->bundle->cfg.auth.name[sizeof arg->bundle->cfg.auth.name-1] = '\0'; 1363 break; 1364 default: 1365 err = "set authname: Only available at phase DEAD/ESTABLISH\n"; 1366 log_Printf(LogWARN, err); 1367 break; 1368 } 1369 break; 1370 1371 case VAR_AUTOLOAD: 1372 if (arg->argc == arg->argn + 2 || arg->argc == arg->argn + 4) { 1373 arg->bundle->autoload.running = 1; 1374 arg->bundle->cfg.autoload.max.timeout = atoi(arg->argv[arg->argn]); 1375 arg->bundle->cfg.autoload.max.packets = atoi(arg->argv[arg->argn + 1]); 1376 if (arg->argc == arg->argn + 4) { 1377 arg->bundle->cfg.autoload.min.timeout = atoi(arg->argv[arg->argn + 2]); 1378 arg->bundle->cfg.autoload.min.packets = atoi(arg->argv[arg->argn + 3]); 1379 } else { 1380 arg->bundle->cfg.autoload.min.timeout = 0; 1381 arg->bundle->cfg.autoload.min.packets = 0; 1382 } 1383 } else { 1384 err = "Set autoload requires two or four arguments\n"; 1385 log_Printf(LogWARN, err); 1386 } 1387 break; 1388 1389 case VAR_DIAL: 1390 strncpy(cx->cfg.script.dial, argp, sizeof cx->cfg.script.dial - 1); 1391 cx->cfg.script.dial[sizeof cx->cfg.script.dial - 1] = '\0'; 1392 break; 1393 1394 case VAR_LOGIN: 1395 strncpy(cx->cfg.script.login, argp, sizeof cx->cfg.script.login - 1); 1396 cx->cfg.script.login[sizeof cx->cfg.script.login - 1] = '\0'; 1397 break; 1398 1399 case VAR_WINSIZE: 1400 if (arg->argc > arg->argn) { 1401 l->ccp.cfg.deflate.out.winsize = atoi(arg->argv[arg->argn]); 1402 if (l->ccp.cfg.deflate.out.winsize < 8 || 1403 l->ccp.cfg.deflate.out.winsize > 15) { 1404 log_Printf(LogWARN, "%d: Invalid outgoing window size\n", 1405 l->ccp.cfg.deflate.out.winsize); 1406 l->ccp.cfg.deflate.out.winsize = 15; 1407 } 1408 if (arg->argc > arg->argn+1) { 1409 l->ccp.cfg.deflate.in.winsize = atoi(arg->argv[arg->argn+1]); 1410 if (l->ccp.cfg.deflate.in.winsize < 8 || 1411 l->ccp.cfg.deflate.in.winsize > 15) { 1412 log_Printf(LogWARN, "%d: Invalid incoming window size\n", 1413 l->ccp.cfg.deflate.in.winsize); 1414 l->ccp.cfg.deflate.in.winsize = 15; 1415 } 1416 } else 1417 l->ccp.cfg.deflate.in.winsize = 0; 1418 } else { 1419 err = "No window size specified\n"; 1420 log_Printf(LogWARN, err); 1421 } 1422 break; 1423 1424 case VAR_DEVICE: 1425 physical_SetDeviceList(cx->physical, arg->argc - arg->argn, 1426 arg->argv + arg->argn); 1427 break; 1428 1429 case VAR_ACCMAP: 1430 if (arg->argc > arg->argn) { 1431 u_long ulong_val; 1432 sscanf(argp, "%lx", &ulong_val); 1433 cx->physical->link.lcp.cfg.accmap = (u_int32_t)ulong_val; 1434 } else { 1435 err = "No accmap specified\n"; 1436 log_Printf(LogWARN, err); 1437 } 1438 break; 1439 1440 case VAR_MODE: 1441 mode = Nam2mode(argp); 1442 if (mode == PHYS_NONE || mode == PHYS_ALL) { 1443 log_Printf(LogWARN, "%s: Invalid mode\n", argp); 1444 return -1; 1445 } 1446 bundle_SetMode(arg->bundle, cx, mode); 1447 break; 1448 1449 case VAR_MRRU: 1450 switch (bundle_Phase(arg->bundle)) { 1451 case PHASE_DEAD: 1452 break; 1453 case PHASE_ESTABLISH: 1454 /* Make sure none of our links are DATALINK_LCP or greater */ 1455 if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) { 1456 log_Printf(LogWARN, "mrru: Only changable before LCP negotiations\n"); 1457 return 1; 1458 } 1459 break; 1460 default: 1461 log_Printf(LogWARN, "mrru: Only changable at phase DEAD/ESTABLISH\n"); 1462 return 1; 1463 } 1464 long_val = atol(argp); 1465 if (long_val && long_val < MIN_MRU) { 1466 log_Printf(LogWARN, "MRRU %ld: too small - min %d\n", long_val, MIN_MRU); 1467 return 1; 1468 } else if (long_val > MAX_MRU) { 1469 log_Printf(LogWARN, "MRRU %ld: too big - max %d\n", long_val, MAX_MRU); 1470 return 1; 1471 } else 1472 arg->bundle->ncp.mp.cfg.mrru = long_val; 1473 break; 1474 1475 case VAR_MRU: 1476 long_val = atol(argp); 1477 if (long_val == 0) 1478 l->lcp.cfg.mru = DEF_MRU; 1479 else if (long_val < MIN_MRU) { 1480 log_Printf(LogWARN, "MRU %ld: too small - min %d\n", long_val, MIN_MRU); 1481 return 1; 1482 } else if (long_val > MAX_MRU) { 1483 log_Printf(LogWARN, "MRU %ld: too big - max %d\n", long_val, MAX_MRU); 1484 return 1; 1485 } else 1486 l->lcp.cfg.mru = long_val; 1487 break; 1488 1489 case VAR_MTU: 1490 long_val = atol(argp); 1491 if (long_val && long_val < MIN_MTU) { 1492 log_Printf(LogWARN, "MTU %ld: too small - min %d\n", long_val, MIN_MTU); 1493 return 1; 1494 } else if (long_val > MAX_MTU) { 1495 log_Printf(LogWARN, "MTU %ld: too big - max %d\n", long_val, MAX_MTU); 1496 return 1; 1497 } else 1498 arg->bundle->cfg.mtu = long_val; 1499 break; 1500 1501 case VAR_OPENMODE: 1502 if (strcasecmp(argp, "active") == 0) 1503 cx->physical->link.lcp.cfg.openmode = arg->argc > arg->argn+1 ? 1504 atoi(arg->argv[arg->argn+1]) : 1; 1505 else if (strcasecmp(argp, "passive") == 0) 1506 cx->physical->link.lcp.cfg.openmode = OPEN_PASSIVE; 1507 else { 1508 err = "%s: Invalid openmode\n"; 1509 log_Printf(LogWARN, err, argp); 1510 } 1511 break; 1512 1513 case VAR_PHONE: 1514 strncpy(cx->cfg.phone.list, argp, sizeof cx->cfg.phone.list - 1); 1515 cx->cfg.phone.list[sizeof cx->cfg.phone.list - 1] = '\0'; 1516 cx->phone.alt = cx->phone.next = NULL; 1517 break; 1518 1519 case VAR_HANGUP: 1520 strncpy(cx->cfg.script.hangup, argp, sizeof cx->cfg.script.hangup - 1); 1521 cx->cfg.script.hangup[sizeof cx->cfg.script.hangup - 1] = '\0'; 1522 break; 1523 1524 case VAR_IDLETIMEOUT: 1525 if (arg->argc > arg->argn+1) 1526 err = "Too many idle timeout values\n"; 1527 else if (arg->argc == arg->argn+1) 1528 bundle_SetIdleTimer(arg->bundle, atoi(argp)); 1529 if (err) 1530 log_Printf(LogWARN, err); 1531 break; 1532 1533 case VAR_LQRPERIOD: 1534 long_val = atol(argp); 1535 if (long_val < MIN_LQRPERIOD) { 1536 log_Printf(LogWARN, "%ld: Invalid lqr period - min %d\n", 1537 long_val, MIN_LQRPERIOD); 1538 return 1; 1539 } else 1540 l->lcp.cfg.lqrperiod = long_val; 1541 break; 1542 1543 case VAR_LCPRETRY: 1544 long_val = atol(argp); 1545 if (long_val < MIN_FSMRETRY) { 1546 log_Printf(LogWARN, "%ld: Invalid LCP FSM retry period - min %d\n", 1547 long_val, MIN_FSMRETRY); 1548 return 1; 1549 } else 1550 cx->physical->link.lcp.cfg.fsmretry = long_val; 1551 break; 1552 1553 case VAR_CHAPRETRY: 1554 long_val = atol(argp); 1555 if (long_val < MIN_FSMRETRY) { 1556 log_Printf(LogWARN, "%ld: Invalid CHAP FSM retry period - min %d\n", 1557 long_val, MIN_FSMRETRY); 1558 return 1; 1559 } else 1560 cx->chap.auth.cfg.fsmretry = long_val; 1561 break; 1562 1563 case VAR_PAPRETRY: 1564 long_val = atol(argp); 1565 if (long_val < MIN_FSMRETRY) { 1566 log_Printf(LogWARN, "%ld: Invalid PAP FSM retry period - min %d\n", 1567 long_val, MIN_FSMRETRY); 1568 return 1; 1569 } else 1570 cx->pap.cfg.fsmretry = long_val; 1571 break; 1572 1573 case VAR_CCPRETRY: 1574 long_val = atol(argp); 1575 if (long_val < MIN_FSMRETRY) { 1576 log_Printf(LogWARN, "%ld: Invalid CCP FSM retry period - min %d\n", 1577 long_val, MIN_FSMRETRY); 1578 return 1; 1579 } else 1580 l->ccp.cfg.fsmretry = long_val; 1581 break; 1582 1583 case VAR_IPCPRETRY: 1584 long_val = atol(argp); 1585 if (long_val < MIN_FSMRETRY) { 1586 log_Printf(LogWARN, "%ld: Invalid IPCP FSM retry period - min %d\n", 1587 long_val, MIN_FSMRETRY); 1588 return 1; 1589 } else 1590 arg->bundle->ncp.ipcp.cfg.fsmretry = long_val; 1591 break; 1592 1593 case VAR_NBNS: 1594 case VAR_DNS: 1595 if (param == VAR_DNS) 1596 addr = arg->bundle->ncp.ipcp.cfg.ns.dns; 1597 else 1598 addr = arg->bundle->ncp.ipcp.cfg.ns.nbns; 1599 1600 addr[0].s_addr = addr[1].s_addr = INADDR_ANY; 1601 1602 if (arg->argc > arg->argn) { 1603 ParseAddr(&arg->bundle->ncp.ipcp, 1, arg->argv + arg->argn, 1604 addr, &dummyaddr, &dummyint); 1605 if (arg->argc > arg->argn+1) 1606 ParseAddr(&arg->bundle->ncp.ipcp, 1, arg->argv + arg->argn + 1, 1607 addr + 1, &dummyaddr, &dummyint); 1608 1609 if (addr[1].s_addr == INADDR_ANY) 1610 addr[1].s_addr = addr[0].s_addr; 1611 if (addr[0].s_addr == INADDR_ANY) 1612 addr[0].s_addr = addr[1].s_addr; 1613 } 1614 break; 1615 1616 case VAR_CALLBACK: 1617 cx->cfg.callback.opmask = 0; 1618 for (dummyint = arg->argn; dummyint < arg->argc; dummyint++) { 1619 if (!strcasecmp(arg->argv[dummyint], "auth")) 1620 cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_AUTH); 1621 else if (!strcasecmp(arg->argv[dummyint], "cbcp")) 1622 cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_CBCP); 1623 else if (!strcasecmp(arg->argv[dummyint], "e.164")) { 1624 if (dummyint == arg->argc - 1) 1625 log_Printf(LogWARN, "No E.164 arg (E.164 ignored) !\n"); 1626 else { 1627 cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_E164); 1628 strncpy(cx->cfg.callback.msg, arg->argv[++dummyint], 1629 sizeof cx->cfg.callback.msg - 1); 1630 cx->cfg.callback.msg[sizeof cx->cfg.callback.msg - 1] = '\0'; 1631 } 1632 } else if (!strcasecmp(arg->argv[dummyint], "none")) 1633 cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_NONE); 1634 else 1635 return -1; 1636 } 1637 if (cx->cfg.callback.opmask == CALLBACK_BIT(CALLBACK_NONE)) 1638 cx->cfg.callback.opmask = 0; 1639 break; 1640 1641 case VAR_CBCP: 1642 cx->cfg.cbcp.delay = 0; 1643 *cx->cfg.cbcp.phone = '\0'; 1644 cx->cfg.cbcp.fsmretry = DEF_FSMRETRY; 1645 if (arg->argc > arg->argn) { 1646 strncpy(cx->cfg.cbcp.phone, arg->argv[arg->argn], 1647 sizeof cx->cfg.cbcp.phone - 1); 1648 cx->cfg.cbcp.phone[sizeof cx->cfg.cbcp.phone - 1] = '\0'; 1649 if (arg->argc > arg->argn + 1) { 1650 cx->cfg.cbcp.delay = atoi(arg->argv[arg->argn + 1]); 1651 if (arg->argc > arg->argn + 2) { 1652 long_val = atol(arg->argv[arg->argn + 2]); 1653 if (long_val < MIN_FSMRETRY) 1654 log_Printf(LogWARN, "%ld: Invalid CBCP FSM retry period - min %d\n", 1655 long_val, MIN_FSMRETRY); 1656 else 1657 cx->cfg.cbcp.fsmretry = long_val; 1658 } 1659 } 1660 } 1661 break; 1662 1663 case VAR_CHOKED: 1664 arg->bundle->cfg.choked.timeout = atoi(argp); 1665 if (arg->bundle->cfg.choked.timeout <= 0) 1666 arg->bundle->cfg.choked.timeout = CHOKED_TIMEOUT; 1667 break; 1668 1669 } 1670 1671 return err ? 1 : 0; 1672} 1673 1674static int 1675SetCtsRts(struct cmdargs const *arg) 1676{ 1677 if (arg->argc == arg->argn+1) { 1678 if (strcmp(arg->argv[arg->argn], "on") == 0) 1679 physical_SetRtsCts(arg->cx->physical, 1); 1680 else if (strcmp(arg->argv[arg->argn], "off") == 0) 1681 physical_SetRtsCts(arg->cx->physical, 0); 1682 else 1683 return -1; 1684 return 0; 1685 } 1686 return -1; 1687} 1688 1689static struct cmdtab const SetCommands[] = { 1690 {"accmap", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, 1691 "accmap value", "set accmap hex-value", (const void *)VAR_ACCMAP}, 1692 {"authkey", "key", SetVariable, LOCAL_AUTH, 1693 "authentication key", "set authkey|key key", (const void *)VAR_AUTHKEY}, 1694 {"authname", NULL, SetVariable, LOCAL_AUTH, 1695 "authentication name", "set authname name", (const void *)VAR_AUTHNAME}, 1696 {"autoload", NULL, SetVariable, LOCAL_AUTH, 1697 "auto link [de]activation", "set autoload maxtime maxload mintime minload", 1698 (const void *)VAR_AUTOLOAD}, 1699 {"callback", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, 1700 "callback control", "set callback [none|auth|cbcp|" 1701 "E.164 *|number[,number]...]...", (const void *)VAR_CALLBACK}, 1702 {"cbcp", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, 1703 "CBCP control", "set cbcp [*|phone[,phone...] [delay [timeout]]]", 1704 (const void *)VAR_CBCP}, 1705 {"ccpretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT, 1706 "FSM retry period", "set ccpretry value", (const void *)VAR_CCPRETRY}, 1707 {"chapretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, 1708 "CHAP retry period", "set chapretry value", (const void *)VAR_CHAPRETRY}, 1709 {"choked", NULL, SetVariable, LOCAL_AUTH, 1710 "choked timeout", "set choked [secs]", (const void *)VAR_CHOKED}, 1711 {"ctsrts", "crtscts", SetCtsRts, LOCAL_AUTH | LOCAL_CX, 1712 "Use hardware flow control", "set ctsrts [on|off]"}, 1713 {"deflate", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT, 1714 "deflate window sizes", "set deflate out-winsize in-winsize", 1715 (const void *) VAR_WINSIZE}, 1716 {"device", "line", SetVariable, LOCAL_AUTH | LOCAL_CX, 1717 "modem device name", "set device|line device-name[,device-name]", 1718 (const void *) VAR_DEVICE}, 1719 {"dial", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, 1720 "dialing script", "set dial chat-script", (const void *) VAR_DIAL}, 1721 {"dns", NULL, SetVariable, LOCAL_AUTH, "Domain Name Server", 1722 "set dns pri-addr [sec-addr]", (const void *)VAR_DNS}, 1723 {"enddisc", NULL, mp_SetEnddisc, LOCAL_AUTH, 1724 "Endpoint Discriminator", "set enddisc [IP|magic|label|psn value]"}, 1725 {"escape", NULL, SetEscape, LOCAL_AUTH | LOCAL_CX, 1726 "escape characters", "set escape hex-digit ..."}, 1727 {"filter", NULL, filter_Set, LOCAL_AUTH, 1728 "packet filters", "set filter alive|dial|in|out rule-no permit|deny " 1729 "[src_addr[/width]] [dst_addr[/width]] [tcp|udp|icmp [src [lt|eq|gt port]] " 1730 "[dst [lt|eq|gt port]] [estab] [syn] [finrst]]"}, 1731 {"hangup", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, 1732 "hangup script", "set hangup chat-script", (const void *) VAR_HANGUP}, 1733 {"ifaddr", NULL, SetInterfaceAddr, LOCAL_AUTH, "destination address", 1734 "set ifaddr [src-addr [dst-addr [netmask [trg-addr]]]]"}, 1735 {"ipcpretry", NULL, SetVariable, LOCAL_AUTH, 1736 "FSM retry period", "set ipcpretry value", (const void *)VAR_IPCPRETRY}, 1737 {"lcpretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, 1738 "FSM retry period", "set lcpretry value", (const void *)VAR_LCPRETRY}, 1739 {"log", NULL, log_SetLevel, LOCAL_AUTH, "log level", 1740 "set log [local] [+|-]async|cbcp|ccp|chat|command|connect|debug|hdlc|id0|" 1741 "ipcp|lcp|lqm|phase|tcp/ip|timer|tun..."}, 1742 {"login", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, 1743 "login script", "set login chat-script", (const void *) VAR_LOGIN}, 1744 {"lqrperiod", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT, 1745 "LQR period", "set lqrperiod value", (const void *)VAR_LQRPERIOD}, 1746 {"mode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "mode value", 1747 "set mode interactive|auto|ddial|background", (const void *)VAR_MODE}, 1748 {"mrru", NULL, SetVariable, LOCAL_AUTH, "MRRU value", 1749 "set mrru value", (const void *)VAR_MRRU}, 1750 {"mru", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT, 1751 "MRU value", "set mru value", (const void *)VAR_MRU}, 1752 {"mtu", NULL, SetVariable, LOCAL_AUTH, 1753 "interface MTU value", "set mtu value", (const void *)VAR_MTU}, 1754 {"nbns", NULL, SetVariable, LOCAL_AUTH, "NetBIOS Name Server", 1755 "set nbns pri-addr [sec-addr]", (const void *)VAR_NBNS}, 1756 {"openmode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "open mode", 1757 "set openmode active|passive [secs]", (const void *)VAR_OPENMODE}, 1758 {"papretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, 1759 "PAP retry period", "set papretry value", (const void *)VAR_PAPRETRY}, 1760 {"parity", NULL, SetModemParity, LOCAL_AUTH | LOCAL_CX, 1761 "modem parity", "set parity [odd|even|none]"}, 1762 {"phone", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "telephone number(s)", 1763 "set phone phone1[:phone2[...]]", (const void *)VAR_PHONE}, 1764 {"reconnect", NULL, datalink_SetReconnect, LOCAL_AUTH | LOCAL_CX, 1765 "Reconnect timeout", "set reconnect value ntries"}, 1766 {"redial", NULL, datalink_SetRedial, LOCAL_AUTH | LOCAL_CX, 1767 "Redial timeout", "set redial value|random[.value|random] [attempts]"}, 1768 {"server", "socket", SetServer, LOCAL_AUTH, 1769 "server port", "set server|socket TcpPort|LocalName|none password [mask]"}, 1770 {"speed", NULL, SetModemSpeed, LOCAL_AUTH | LOCAL_CX, 1771 "modem speed", "set speed value"}, 1772 {"stopped", NULL, SetStoppedTimeout, LOCAL_AUTH | LOCAL_CX, 1773 "STOPPED timeouts", "set stopped [LCPseconds [CCPseconds]]"}, 1774 {"timeout", NULL, SetVariable, LOCAL_AUTH, "Idle timeout", 1775 "set timeout idletime", (const void *)VAR_IDLETIMEOUT}, 1776 {"vj", NULL, ipcp_vjset, LOCAL_AUTH, 1777 "vj values", "set vj slots|slotcomp [value]"}, 1778 {"weight", NULL, mp_SetDatalinkWeight, LOCAL_AUTH | LOCAL_CX, 1779 "datalink weighting", "set weight n"}, 1780 {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, 1781 "Display this message", "set help|? [command]", SetCommands}, 1782 {NULL, NULL, NULL}, 1783}; 1784 1785static int 1786SetCommand(struct cmdargs const *arg) 1787{ 1788 if (arg->argc > arg->argn) 1789 FindExec(arg->bundle, SetCommands, arg->argc, arg->argn, arg->argv, 1790 arg->prompt, arg->cx); 1791 else if (arg->prompt) 1792 prompt_Printf(arg->prompt, "Use `set ?' to get a list or `set ? <var>' for" 1793 " syntax help.\n"); 1794 else 1795 log_Printf(LogWARN, "set command must have arguments\n"); 1796 1797 return 0; 1798} 1799 1800static int 1801AddCommand(struct cmdargs const *arg) 1802{ 1803 struct in_addr dest, gateway, netmask; 1804 int gw, addrs; 1805 1806 if (arg->argc != arg->argn+3 && arg->argc != arg->argn+2) 1807 return -1; 1808 1809 addrs = 0; 1810 if (arg->argc == arg->argn+2) { 1811 if (!strcasecmp(arg->argv[arg->argn], "default")) 1812 dest.s_addr = netmask.s_addr = INADDR_ANY; 1813 else { 1814 int width; 1815 1816 if (!ParseAddr(&arg->bundle->ncp.ipcp, 1, arg->argv + arg->argn, 1817 &dest, &netmask, &width)) 1818 return -1; 1819 if (!strncasecmp(arg->argv[arg->argn], "MYADDR", 6)) 1820 addrs = ROUTE_DSTMYADDR; 1821 else if (!strncasecmp(arg->argv[arg->argn], "HISADDR", 7)) 1822 addrs = ROUTE_DSTHISADDR; 1823 } 1824 gw = 1; 1825 } else { 1826 if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) { 1827 addrs = ROUTE_DSTMYADDR; 1828 dest = arg->bundle->ncp.ipcp.my_ip; 1829 } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) { 1830 addrs = ROUTE_DSTHISADDR; 1831 dest = arg->bundle->ncp.ipcp.peer_ip; 1832 } else 1833 dest = GetIpAddr(arg->argv[arg->argn]); 1834 netmask = GetIpAddr(arg->argv[arg->argn+1]); 1835 gw = 2; 1836 } 1837 1838 if (strcasecmp(arg->argv[arg->argn+gw], "HISADDR") == 0) { 1839 gateway = arg->bundle->ncp.ipcp.peer_ip; 1840 addrs |= ROUTE_GWHISADDR; 1841 } else 1842 gateway = GetIpAddr(arg->argv[arg->argn+gw]); 1843 1844 if (bundle_SetRoute(arg->bundle, RTM_ADD, dest, gateway, netmask, 1845 arg->cmd->args ? 1 : 0, (addrs & ROUTE_GWHISADDR) ? 1 : 0)) 1846 route_Add(&arg->bundle->ncp.ipcp.route, addrs, dest, netmask, gateway); 1847 1848 return 0; 1849} 1850 1851static int 1852DeleteCommand(struct cmdargs const *arg) 1853{ 1854 struct in_addr dest, none; 1855 int addrs; 1856 1857 if (arg->argc == arg->argn+1) { 1858 if(strcasecmp(arg->argv[arg->argn], "all") == 0) { 1859 route_IfDelete(arg->bundle, 0); 1860 route_DeleteAll(&arg->bundle->ncp.ipcp.route); 1861 } else { 1862 addrs = 0; 1863 if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) { 1864 dest = arg->bundle->ncp.ipcp.my_ip; 1865 addrs = ROUTE_DSTMYADDR; 1866 } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) { 1867 dest = arg->bundle->ncp.ipcp.peer_ip; 1868 addrs = ROUTE_DSTHISADDR; 1869 } else { 1870 if (strcasecmp(arg->argv[arg->argn], "default") == 0) 1871 dest.s_addr = INADDR_ANY; 1872 else 1873 dest = GetIpAddr(arg->argv[arg->argn]); 1874 addrs = ROUTE_STATIC; 1875 } 1876 none.s_addr = INADDR_ANY; 1877 bundle_SetRoute(arg->bundle, RTM_DELETE, dest, none, none, 1878 arg->cmd->args ? 1 : 0, 0); 1879 route_Delete(&arg->bundle->ncp.ipcp.route, addrs, dest); 1880 } 1881 } else 1882 return -1; 1883 1884 return 0; 1885} 1886 1887#ifndef NOALIAS 1888static int 1889AliasEnable(struct cmdargs const *arg) 1890{ 1891 if (arg->argc == arg->argn+1) { 1892 if (strcasecmp(arg->argv[arg->argn], "yes") == 0) { 1893 arg->bundle->AliasEnabled = 1; 1894 return 0; 1895 } else if (strcasecmp(arg->argv[arg->argn], "no") == 0) { 1896 arg->bundle->AliasEnabled = 0; 1897 arg->bundle->cfg.opt &= ~OPT_IFACEALIAS; 1898 /* Don't iface_Clear() - there may be manually configured addresses */ 1899 return 0; 1900 } 1901 } 1902 1903 return -1; 1904} 1905 1906 1907static int 1908AliasOption(struct cmdargs const *arg) 1909{ 1910 long param = (long)arg->cmd->args; 1911 1912 if (arg->argc == arg->argn+1) { 1913 if (strcasecmp(arg->argv[arg->argn], "yes") == 0) { 1914 if (arg->bundle->AliasEnabled) { 1915 PacketAliasSetMode(param, param); 1916 return 0; 1917 } 1918 log_Printf(LogWARN, "alias not enabled\n"); 1919 } else if (strcmp(arg->argv[arg->argn], "no") == 0) { 1920 if (arg->bundle->AliasEnabled) { 1921 PacketAliasSetMode(0, param); 1922 return 0; 1923 } 1924 log_Printf(LogWARN, "alias not enabled\n"); 1925 } 1926 } 1927 return -1; 1928} 1929#endif /* #ifndef NOALIAS */ 1930 1931static int 1932LinkCommand(struct cmdargs const *arg) 1933{ 1934 if (arg->argc > arg->argn+1) { 1935 char namelist[LINE_LEN]; 1936 struct datalink *cx; 1937 char *name; 1938 int result = 0; 1939 1940 if (!strcmp(arg->argv[arg->argn], "*")) { 1941 struct datalink *dl; 1942 1943 cx = arg->bundle->links; 1944 while (cx) { 1945 /* Watch it, the command could be a ``remove'' */ 1946 dl = cx->next; 1947 FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv, 1948 arg->prompt, cx); 1949 for (cx = arg->bundle->links; cx; cx = cx->next) 1950 if (cx == dl) 1951 break; /* Pointer's still valid ! */ 1952 } 1953 } else { 1954 strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1); 1955 namelist[sizeof namelist - 1] = '\0'; 1956 for(name = strtok(namelist, ", "); name; name = strtok(NULL,", ")) 1957 if (!bundle2datalink(arg->bundle, name)) { 1958 log_Printf(LogWARN, "link: %s: Invalid link name\n", name); 1959 return 1; 1960 } 1961 1962 strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1); 1963 namelist[sizeof namelist - 1] = '\0'; 1964 for(name = strtok(namelist, ", "); name; name = strtok(NULL,", ")) { 1965 cx = bundle2datalink(arg->bundle, name); 1966 if (cx) 1967 FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv, 1968 arg->prompt, cx); 1969 else { 1970 log_Printf(LogWARN, "link: %s: Invalidated link name !\n", name); 1971 result++; 1972 } 1973 } 1974 } 1975 return result; 1976 } 1977 1978 log_Printf(LogWARN, "Usage: %s\n", arg->cmd->syntax); 1979 return 2; 1980} 1981 1982struct link * 1983command_ChooseLink(struct cmdargs const *arg) 1984{ 1985 if (arg->cx) 1986 return &arg->cx->physical->link; 1987 else if (!arg->bundle->ncp.mp.cfg.mrru) { 1988 struct datalink *dl = bundle2datalink(arg->bundle, NULL); 1989 if (dl) 1990 return &dl->physical->link; 1991 } 1992 return &arg->bundle->ncp.mp.link; 1993} 1994 1995static const char * 1996ident_cmd(const char *cmd, unsigned *keep, unsigned *add) 1997{ 1998 const char *result; 1999 2000 switch (*cmd) { 2001 case 'A': 2002 case 'a': 2003 result = "accept"; 2004 *keep = NEG_MYMASK; 2005 *add = NEG_ACCEPTED; 2006 break; 2007 case 'D': 2008 case 'd': 2009 switch (cmd[1]) { 2010 case 'E': 2011 case 'e': 2012 result = "deny"; 2013 *keep = NEG_MYMASK; 2014 *add = 0; 2015 break; 2016 case 'I': 2017 case 'i': 2018 result = "disable"; 2019 *keep = NEG_HISMASK; 2020 *add = 0; 2021 break; 2022 default: 2023 return NULL; 2024 } 2025 break; 2026 case 'E': 2027 case 'e': 2028 result = "enable"; 2029 *keep = NEG_HISMASK; 2030 *add = NEG_ENABLED; 2031 break; 2032 default: 2033 return NULL; 2034 } 2035 2036 return result; 2037} 2038 2039static int 2040OptSet(struct cmdargs const *arg) 2041{ 2042 int bit = (int)(long)arg->cmd->args; 2043 const char *cmd; 2044 unsigned keep; /* Keep these bits */ 2045 unsigned add; /* Add these bits */ 2046 2047 if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL) 2048 return 1; 2049 2050 if (add) 2051 arg->bundle->cfg.opt |= bit; 2052 else 2053 arg->bundle->cfg.opt &= ~bit; 2054 return 0; 2055} 2056 2057static int 2058IfaceAliasOptSet(struct cmdargs const *arg) 2059{ 2060 unsigned save = arg->bundle->cfg.opt; 2061 int result = OptSet(arg); 2062 2063 if (result == 0) 2064 if (Enabled(arg->bundle, OPT_IFACEALIAS) && !arg->bundle->AliasEnabled) { 2065 arg->bundle->cfg.opt = save; 2066 log_Printf(LogWARN, "Cannot enable iface-alias without IP aliasing\n"); 2067 result = 2; 2068 } 2069 2070 return result; 2071} 2072 2073static int 2074NegotiateSet(struct cmdargs const *arg) 2075{ 2076 long param = (long)arg->cmd->args; 2077 struct link *l = command_ChooseLink(arg); /* LOCAL_CX_OPT uses this */ 2078 struct datalink *cx = arg->cx; /* LOCAL_CX uses this */ 2079 const char *cmd; 2080 unsigned keep; /* Keep these bits */ 2081 unsigned add; /* Add these bits */ 2082 2083 if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL) 2084 return 1; 2085 2086 if ((arg->cmd->lauth & LOCAL_CX) && !cx) { 2087 log_Printf(LogWARN, "%s %s: No context (use the `link' command)\n", 2088 cmd, arg->cmd->name); 2089 return 2; 2090 } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) { 2091 log_Printf(LogWARN, "%s %s: Redundant context (%s) ignored\n", 2092 cmd, arg->cmd->name, cx->name); 2093 cx = NULL; 2094 } 2095 2096 switch (param) { 2097 case NEG_ACFCOMP: 2098 cx->physical->link.lcp.cfg.acfcomp &= keep; 2099 cx->physical->link.lcp.cfg.acfcomp |= add; 2100 break; 2101 case NEG_CHAP: 2102 cx->physical->link.lcp.cfg.chap &= keep; 2103 cx->physical->link.lcp.cfg.chap |= add; 2104 break; 2105 case NEG_DEFLATE: 2106 l->ccp.cfg.neg[CCP_NEG_DEFLATE] &= keep; 2107 l->ccp.cfg.neg[CCP_NEG_DEFLATE] |= add; 2108 break; 2109 case NEG_DNS: 2110 arg->bundle->ncp.ipcp.cfg.ns.dns_neg &= keep; 2111 arg->bundle->ncp.ipcp.cfg.ns.dns_neg |= add; 2112 break; 2113 case NEG_LQR: 2114 cx->physical->link.lcp.cfg.lqr &= keep; 2115 cx->physical->link.lcp.cfg.lqr |= add; 2116 break; 2117 case NEG_PAP: 2118 cx->physical->link.lcp.cfg.pap &= keep; 2119 cx->physical->link.lcp.cfg.pap |= add; 2120 break; 2121 case NEG_PPPDDEFLATE: 2122 l->ccp.cfg.neg[CCP_NEG_DEFLATE24] &= keep; 2123 l->ccp.cfg.neg[CCP_NEG_DEFLATE24] |= add; 2124 break; 2125 case NEG_PRED1: 2126 l->ccp.cfg.neg[CCP_NEG_PRED1] &= keep; 2127 l->ccp.cfg.neg[CCP_NEG_PRED1] |= add; 2128 break; 2129 case NEG_PROTOCOMP: 2130 cx->physical->link.lcp.cfg.protocomp &= keep; 2131 cx->physical->link.lcp.cfg.protocomp |= add; 2132 break; 2133 case NEG_SHORTSEQ: 2134 switch (bundle_Phase(arg->bundle)) { 2135 case PHASE_DEAD: 2136 break; 2137 case PHASE_ESTABLISH: 2138 /* Make sure none of our links are DATALINK_LCP or greater */ 2139 if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) { 2140 log_Printf(LogWARN, "shortseq: Only changable before" 2141 " LCP negotiations\n"); 2142 return 1; 2143 } 2144 break; 2145 default: 2146 log_Printf(LogWARN, "shortseq: Only changable at phase" 2147 " DEAD/ESTABLISH\n"); 2148 return 1; 2149 } 2150 arg->bundle->ncp.mp.cfg.shortseq &= keep; 2151 arg->bundle->ncp.mp.cfg.shortseq |= add; 2152 break; 2153 case NEG_VJCOMP: 2154 arg->bundle->ncp.ipcp.cfg.vj.neg &= keep; 2155 arg->bundle->ncp.ipcp.cfg.vj.neg |= add; 2156 break; 2157 } 2158 2159 return 0; 2160} 2161 2162static struct cmdtab const NegotiateCommands[] = { 2163 {"idcheck", NULL, OptSet, LOCAL_AUTH, "Check FSM reply ids", 2164 "disable|enable", (const void *)OPT_IDCHECK}, 2165 {"loopback", NULL, OptSet, LOCAL_AUTH, "Loop packets for local iface", 2166 "disable|enable", (const void *)OPT_LOOPBACK}, 2167 {"passwdauth", NULL, OptSet, LOCAL_AUTH, "Use passwd file", 2168 "disable|enable", (const void *)OPT_PASSWDAUTH}, 2169 {"proxy", NULL, OptSet, LOCAL_AUTH, "Create proxy ARP entry", 2170 "disable|enable", (const void *)OPT_PROXY}, 2171 {"sroutes", NULL, OptSet, LOCAL_AUTH, "Use sticky routes", 2172 "disable|enable", (const void *)OPT_SROUTES}, 2173 {"throughput", NULL, OptSet, LOCAL_AUTH, "Rolling throughput", 2174 "disable|enable", (const void *)OPT_THROUGHPUT}, 2175 {"utmp", NULL, OptSet, LOCAL_AUTH, "Log connections in utmp", 2176 "disable|enable", (const void *)OPT_UTMP}, 2177 {"iface-alias", NULL, IfaceAliasOptSet, LOCAL_AUTH, 2178 "maintain interface addresses", "disable|enable", 2179 (const void *)OPT_IFACEALIAS}, 2180 2181#define OPT_MAX 8 /* accept/deny allowed below and not above */ 2182 2183 {"acfcomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX, 2184 "Address & Control field compression", "accept|deny|disable|enable", 2185 (const void *)NEG_ACFCOMP}, 2186 {"chap", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX, 2187 "Challenge Handshake Authentication Protocol", "accept|deny|disable|enable", 2188 (const void *)NEG_CHAP}, 2189 {"deflate", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT, 2190 "Deflate compression", "accept|deny|disable|enable", 2191 (const void *)NEG_DEFLATE}, 2192 {"deflate24", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT, 2193 "Deflate (type 24) compression", "accept|deny|disable|enable", 2194 (const void *)NEG_PPPDDEFLATE}, 2195 {"dns", NULL, NegotiateSet, LOCAL_AUTH, 2196 "DNS specification", "accept|deny|disable|enable", (const void *)NEG_DNS}, 2197 {"lqr", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX, 2198 "Link Quality Reports", "accept|deny|disable|enable", 2199 (const void *)NEG_LQR}, 2200 {"pap", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX, 2201 "Password Authentication protocol", "accept|deny|disable|enable", 2202 (const void *)NEG_PAP}, 2203 {"pred1", "predictor1", NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT, 2204 "Predictor 1 compression", "accept|deny|disable|enable", 2205 (const void *)NEG_PRED1}, 2206 {"protocomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX, 2207 "Protocol field compression", "accept|deny|disable|enable", 2208 (const void *)NEG_PROTOCOMP}, 2209 {"shortseq", NULL, NegotiateSet, LOCAL_AUTH, 2210 "MP Short Sequence Numbers", "accept|deny|disable|enable", 2211 (const void *)NEG_SHORTSEQ}, 2212 {"vjcomp", NULL, NegotiateSet, LOCAL_AUTH, 2213 "Van Jacobson header compression", "accept|deny|disable|enable", 2214 (const void *)NEG_VJCOMP}, 2215 {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, 2216 "Display this message", "accept|deny|disable|enable help|? [value]", 2217 NegotiateCommands}, 2218 {NULL, NULL, NULL}, 2219}; 2220 2221static int 2222NegotiateCommand(struct cmdargs const *arg) 2223{ 2224 if (arg->argc > arg->argn) { 2225 char const *argv[3]; 2226 unsigned keep, add; 2227 int n; 2228 2229 if ((argv[0] = ident_cmd(arg->argv[arg->argn-1], &keep, &add)) == NULL) 2230 return -1; 2231 argv[2] = NULL; 2232 2233 for (n = arg->argn; n < arg->argc; n++) { 2234 argv[1] = arg->argv[n]; 2235 FindExec(arg->bundle, NegotiateCommands + (keep == NEG_HISMASK ? 2236 0 : OPT_MAX), 2, 1, argv, arg->prompt, arg->cx); 2237 } 2238 } else if (arg->prompt) 2239 prompt_Printf(arg->prompt, "Use `%s ?' to get a list.\n", 2240 arg->argv[arg->argn-1]); 2241 else 2242 log_Printf(LogWARN, "%s command must have arguments\n", 2243 arg->argv[arg->argn] ); 2244 2245 return 0; 2246} 2247 2248const char * 2249command_ShowNegval(unsigned val) 2250{ 2251 switch (val&3) { 2252 case 1: return "disabled & accepted"; 2253 case 2: return "enabled & denied"; 2254 case 3: return "enabled & accepted"; 2255 } 2256 return "disabled & denied"; 2257} 2258 2259static int 2260ClearCommand(struct cmdargs const *arg) 2261{ 2262 struct pppThroughput *t; 2263 struct datalink *cx; 2264 int i, clear_type; 2265 2266 if (arg->argc < arg->argn + 1) 2267 return -1; 2268 2269 if (strcasecmp(arg->argv[arg->argn], "modem") == 0) { 2270 cx = arg->cx; 2271 if (!cx) 2272 cx = bundle2datalink(arg->bundle, NULL); 2273 if (!cx) { 2274 log_Printf(LogWARN, "A link must be specified for ``clear modem''\n"); 2275 return 1; 2276 } 2277 t = &cx->physical->link.throughput; 2278 } else if (strcasecmp(arg->argv[arg->argn], "ipcp") == 0) 2279 t = &arg->bundle->ncp.ipcp.throughput; 2280 else 2281 return -1; 2282 2283 if (arg->argc > arg->argn + 1) { 2284 clear_type = 0; 2285 for (i = arg->argn + 1; i < arg->argc; i++) 2286 if (strcasecmp(arg->argv[i], "overall") == 0) 2287 clear_type |= THROUGHPUT_OVERALL; 2288 else if (strcasecmp(arg->argv[i], "current") == 0) 2289 clear_type |= THROUGHPUT_CURRENT; 2290 else if (strcasecmp(arg->argv[i], "peak") == 0) 2291 clear_type |= THROUGHPUT_PEAK; 2292 else 2293 return -1; 2294 } else 2295 clear_type = THROUGHPUT_ALL; 2296 2297 throughput_clear(t, clear_type, arg->prompt); 2298 return 0; 2299} 2300 2301static int 2302RunListCommand(struct cmdargs const *arg) 2303{ 2304 const char *cmd = arg->argc ? arg->argv[arg->argc - 1] : "???"; 2305 2306 if (arg->argc > arg->argn) 2307 FindExec(arg->bundle, arg->cmd->args, arg->argc, arg->argn, arg->argv, 2308 arg->prompt, arg->cx); 2309 else if (arg->prompt) 2310 prompt_Printf(arg->prompt, "Use `%s help' to get a list or `%s help" 2311 " <option>' for syntax help.\n", cmd, cmd); 2312 else 2313 log_Printf(LogWARN, "%s command must have arguments\n", cmd); 2314 2315 return 0; 2316} 2317 2318static int 2319IfaceAddCommand(struct cmdargs const *arg) 2320{ 2321 int bits, n, how; 2322 struct in_addr ifa, mask, brd; 2323 2324 if (arg->argc == arg->argn + 2) { 2325 if (!ParseAddr(NULL, 1, arg->argv + arg->argn, &ifa, &mask, &bits)) 2326 return -1; 2327 n = 1; 2328 } else if (arg->argc == arg->argn + 3) { 2329 if (!ParseAddr(NULL, 1, arg->argv + arg->argn, &ifa, NULL, NULL)) 2330 return -1; 2331 if (!ParseAddr(NULL, 1, arg->argv + arg->argn + 1, &mask, NULL, NULL)) 2332 return -1; 2333 n = 2; 2334 } else 2335 return -1; 2336 2337 if (!ParseAddr(NULL, 1, arg->argv + arg->argn + n, &brd, NULL, NULL)) 2338 return -1; 2339 2340 how = IFACE_ADD_LAST; 2341 if (arg->cmd->args) 2342 how |= IFACE_FORCE_ADD; 2343 2344 return !iface_inAdd(arg->bundle->iface, ifa, mask, brd, how); 2345} 2346 2347static int 2348IfaceDeleteCommand(struct cmdargs const *arg) 2349{ 2350 struct in_addr ifa; 2351 int ok; 2352 2353 if (arg->argc != arg->argn + 1) 2354 return -1; 2355 2356 if (!ParseAddr(NULL, 1, arg->argv + arg->argn, &ifa, NULL, NULL)) 2357 return -1; 2358 2359 if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED && 2360 arg->bundle->ncp.ipcp.my_ip.s_addr == ifa.s_addr) { 2361 log_Printf(LogWARN, "%s: Cannot remove active interface address\n", 2362 inet_ntoa(ifa)); 2363 return 1; 2364 } 2365 2366 ok = iface_inDelete(arg->bundle->iface, ifa); 2367 if (!ok) { 2368 if (arg->cmd->args) 2369 ok = 1; 2370 else if (arg->prompt) 2371 prompt_Printf(arg->prompt, "%s: No such address\n", inet_ntoa(ifa)); 2372 else 2373 log_Printf(LogWARN, "%s: No such address\n", inet_ntoa(ifa)); 2374 } 2375 2376 return !ok; 2377} 2378 2379static int 2380IfaceClearCommand(struct cmdargs const *arg) 2381{ 2382 int how; 2383 2384 if (arg->argc != arg->argn) 2385 return -1; 2386 2387 how = arg->bundle->ncp.ipcp.fsm.state == ST_OPENED ? 2388 IFACE_CLEAR_ALIASES : IFACE_CLEAR_ALL; 2389 iface_Clear(arg->bundle->iface, how); 2390 2391 return 0; 2392} 2393