command.c revision 37210
16059Samurai/*
26059Samurai *		PPP User command processing module
36059Samurai *
46059Samurai *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
56059Samurai *
66059Samurai *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
76059Samurai *
86059Samurai * Redistribution and use in source and binary forms are permitted
96059Samurai * provided that the above copyright notice and this paragraph are
106059Samurai * duplicated in all such forms and that any documentation,
116059Samurai * advertising materials, and other materials related to such
126059Samurai * distribution and use acknowledge that the software was developed
136059Samurai * by the Internet Initiative Japan, Inc.  The name of the
146059Samurai * IIJ may not be used to endorse or promote products derived
156059Samurai * from this software without specific prior written permission.
166059Samurai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
176059Samurai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
186059Samurai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
198857Srgrimes *
2037210Sbrian * $Id: command.c,v 1.151 1998/06/27 14:18:02 brian Exp $
218857Srgrimes *
226059Samurai */
2336285Sbrian#include <sys/types.h>
2430715Sbrian#include <netinet/in_systm.h>
2526031Sbrian#include <netinet/in.h>
2630715Sbrian#include <netinet/ip.h>
2726031Sbrian#include <arpa/inet.h>
2830715Sbrian#include <sys/socket.h>
2926031Sbrian#include <net/route.h>
3030715Sbrian#include <netdb.h>
3136285Sbrian#include <sys/un.h>
3230715Sbrian
3331343Sbrian#ifndef NOALIAS
3426031Sbrian#include <alias.h>
3531343Sbrian#endif
3630715Sbrian#include <errno.h>
3726516Sbrian#include <fcntl.h>
3830715Sbrian#include <paths.h>
3930715Sbrian#include <stdio.h>
4030715Sbrian#include <stdlib.h>
4130715Sbrian#include <string.h>
4230715Sbrian#include <sys/wait.h>
4330715Sbrian#include <termios.h>
4430715Sbrian#include <unistd.h>
4530715Sbrian
4637009Sbrian#include "defs.h"
4731343Sbrian#include "command.h"
4830715Sbrian#include "mbuf.h"
4930715Sbrian#include "log.h"
5030715Sbrian#include "timer.h"
516059Samurai#include "fsm.h"
526059Samurai#include "lcp.h"
5331690Sbrian#include "iplist.h"
5436285Sbrian#include "throughput.h"
5536285Sbrian#include "slcompress.h"
566059Samurai#include "ipcp.h"
576059Samurai#include "modem.h"
5831343Sbrian#ifndef NOALIAS
5926031Sbrian#include "alias_cmd.h"
6031343Sbrian#endif
6136285Sbrian#include "lqr.h"
626059Samurai#include "hdlc.h"
6325630Sbrian#include "systems.h"
6436285Sbrian#include "filter.h"
6536285Sbrian#include "descriptor.h"
6630715Sbrian#include "main.h"
6730715Sbrian#include "route.h"
6830715Sbrian#include "ccp.h"
6931080Sbrian#include "auth.h"
7036285Sbrian#include "async.h"
7136285Sbrian#include "link.h"
7236285Sbrian#include "physical.h"
7336285Sbrian#include "mp.h"
7436285Sbrian#include "bundle.h"
7536285Sbrian#include "server.h"
7636285Sbrian#include "prompt.h"
7736285Sbrian#include "chat.h"
7836285Sbrian#include "chap.h"
7936285Sbrian#include "datalink.h"
806059Samurai
8136285Sbrian/* ``set'' values */
8236285Sbrian#define	VAR_AUTHKEY	0
8336285Sbrian#define	VAR_DIAL	1
8436285Sbrian#define	VAR_LOGIN	2
8536285Sbrian#define	VAR_AUTHNAME	3
8636285Sbrian#define	VAR_AUTOLOAD	4
8736285Sbrian#define	VAR_WINSIZE	5
8836285Sbrian#define	VAR_DEVICE	6
8936285Sbrian#define	VAR_ACCMAP	7
9036285Sbrian#define	VAR_MRRU	8
9136285Sbrian#define	VAR_MRU		9
9236285Sbrian#define	VAR_MTU		10
9336285Sbrian#define	VAR_OPENMODE	11
9436285Sbrian#define	VAR_PHONE	12
9536285Sbrian#define	VAR_HANGUP	13
9636285Sbrian#define	VAR_IDLETIMEOUT	14
9736285Sbrian#define	VAR_LQRPERIOD	15
9836285Sbrian#define	VAR_LCPRETRY	16
9936285Sbrian#define	VAR_CHAPRETRY	17
10036285Sbrian#define	VAR_PAPRETRY	18
10136285Sbrian#define	VAR_CCPRETRY	19
10236285Sbrian#define	VAR_IPCPRETRY	20
10336285Sbrian#define	VAR_DNS		21
10436285Sbrian#define	VAR_NBNS	22
10536285Sbrian#define	VAR_MODE	23
1066059Samurai
10736285Sbrian/* ``accept|deny|disable|enable'' masks */
10836285Sbrian#define NEG_HISMASK (1)
10936285Sbrian#define NEG_MYMASK (2)
11036285Sbrian
11136285Sbrian/* ``accept|deny|disable|enable'' values */
11236285Sbrian#define NEG_ACFCOMP	40
11336285Sbrian#define NEG_CHAP	41
11436285Sbrian#define NEG_DEFLATE	42
11536285Sbrian#define NEG_LQR		43
11636285Sbrian#define NEG_PAP		44
11736285Sbrian#define NEG_PPPDDEFLATE	45
11836285Sbrian#define NEG_PRED1	46
11936285Sbrian#define NEG_PROTOCOMP	47
12036285Sbrian#define NEG_SHORTSEQ	48
12136285Sbrian#define NEG_VJCOMP	49
12236285Sbrian#define NEG_DNS		50
12336285Sbrian
12436285Sbrianconst char Version[] = "2.0-beta";
12537210Sbrianconst char VersionDate[] = "$Date: 1998/06/27 14:18:02 $";
12636285Sbrian
12736285Sbrianstatic int ShowCommand(struct cmdargs const *);
12836285Sbrianstatic int TerminalCommand(struct cmdargs const *);
12936285Sbrianstatic int QuitCommand(struct cmdargs const *);
13036285Sbrianstatic int OpenCommand(struct cmdargs const *);
13136285Sbrianstatic int CloseCommand(struct cmdargs const *);
13236285Sbrianstatic int DownCommand(struct cmdargs const *);
13336285Sbrianstatic int AllowCommand(struct cmdargs const *);
13436285Sbrianstatic int SetCommand(struct cmdargs const *);
13536285Sbrianstatic int LinkCommand(struct cmdargs const *);
13636285Sbrianstatic int AddCommand(struct cmdargs const *);
13736285Sbrianstatic int DeleteCommand(struct cmdargs const *);
13836285Sbrianstatic int NegotiateCommand(struct cmdargs const *);
13936934Sbrianstatic int ClearCommand(struct cmdargs const *);
14031343Sbrian#ifndef NOALIAS
14136285Sbrianstatic int AliasCommand(struct cmdargs const *);
14236285Sbrianstatic int AliasEnable(struct cmdargs const *);
14336285Sbrianstatic int AliasOption(struct cmdargs const *);
14431343Sbrian#endif
1456059Samurai
14636285Sbrianstatic const char *
14736285Sbrianshowcx(struct cmdtab const *cmd)
14836285Sbrian{
14936285Sbrian  if (cmd->lauth & LOCAL_CX)
15036285Sbrian    return "(c)";
15136285Sbrian  else if (cmd->lauth & LOCAL_CX_OPT)
15236285Sbrian    return "(o)";
15336285Sbrian
15436285Sbrian  return "";
15536285Sbrian}
15636285Sbrian
1576059Samuraistatic int
15831343SbrianHelpCommand(struct cmdargs const *arg)
1596059Samurai{
16028679Sbrian  struct cmdtab const *cmd;
16136285Sbrian  int n, cmax, dmax, cols, cxlen;
16236285Sbrian  const char *cx;
1636059Samurai
16436285Sbrian  if (!arg->prompt) {
16536285Sbrian    log_Printf(LogWARN, "help: Cannot help without a prompt\n");
16626516Sbrian    return 0;
16736285Sbrian  }
16826516Sbrian
16936285Sbrian  if (arg->argc > arg->argn) {
17036285Sbrian    for (cmd = arg->cmdtab; cmd->name || cmd->alias; cmd++)
17136285Sbrian      if ((cmd->lauth & arg->prompt->auth) &&
17236285Sbrian          ((cmd->name && !strcasecmp(cmd->name, arg->argv[arg->argn])) ||
17336285Sbrian           (cmd->alias && !strcasecmp(cmd->alias, arg->argv[arg->argn])))) {
17436285Sbrian	prompt_Printf(arg->prompt, "%s %s\n", cmd->syntax, showcx(cmd));
17528679Sbrian	return 0;
1766059Samurai      }
17726516Sbrian    return -1;
1786059Samurai  }
17936285Sbrian
18031372Sbrian  cmax = dmax = 0;
18136285Sbrian  for (cmd = arg->cmdtab; cmd->func; cmd++)
18236285Sbrian    if (cmd->name && (cmd->lauth & arg->prompt->auth)) {
18336285Sbrian      if ((n = strlen(cmd->name) + strlen(showcx(cmd))) > cmax)
18431372Sbrian        cmax = n;
18531372Sbrian      if ((n = strlen(cmd->helpmes)) > dmax)
18631372Sbrian        dmax = n;
18731372Sbrian    }
18831372Sbrian
18931372Sbrian  cols = 80 / (dmax + cmax + 3);
1906059Samurai  n = 0;
19136285Sbrian  prompt_Printf(arg->prompt, "(o) = Optional context,"
19236285Sbrian                " (c) = Context required\n");
19336285Sbrian  for (cmd = arg->cmdtab; cmd->func; cmd++)
19436285Sbrian    if (cmd->name && (cmd->lauth & arg->prompt->auth)) {
19536285Sbrian      cx = showcx(cmd);
19636285Sbrian      cxlen = cmax - strlen(cmd->name);
19736285Sbrian      prompt_Printf(arg->prompt, " %s%-*.*s: %-*.*s",
19836285Sbrian              cmd->name, cxlen, cxlen, cx, dmax, dmax, cmd->helpmes);
19931372Sbrian      if (++n % cols == 0)
20036285Sbrian        prompt_Printf(arg->prompt, "\n");
2016059Samurai    }
20231372Sbrian  if (n % cols != 0)
20336285Sbrian    prompt_Printf(arg->prompt, "\n");
20426516Sbrian
20526516Sbrian  return 0;
2066059Samurai}
2076059Samurai
20836285Sbrianstatic int
20936285SbrianCloneCommand(struct cmdargs const *arg)
2106059Samurai{
21136285Sbrian  char namelist[LINE_LEN];
21236285Sbrian  char *name;
21336285Sbrian  int f;
2146059Samurai
21536285Sbrian  if (arg->argc == arg->argn)
21636285Sbrian    return -1;
21736285Sbrian
21836285Sbrian  namelist[sizeof namelist - 1] = '\0';
21936285Sbrian  for (f = arg->argn; f < arg->argc; f++) {
22036285Sbrian    strncpy(namelist, arg->argv[f], sizeof namelist - 1);
22136285Sbrian    for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
22236285Sbrian      bundle_DatalinkClone(arg->bundle, arg->cx, name);
2236059Samurai  }
22436285Sbrian
22536285Sbrian  return 0;
2266059Samurai}
2276059Samurai
2286059Samuraistatic int
22936285SbrianRemoveCommand(struct cmdargs const *arg)
2306059Samurai{
23136285Sbrian  if (arg->argc != arg->argn)
23236285Sbrian    return -1;
23311336Samurai
23436285Sbrian  if (arg->cx->state != DATALINK_CLOSED) {
23536285Sbrian    log_Printf(LogWARN, "remove: Cannot delete links that aren't closed\n");
23636285Sbrian    return 2;
2376059Samurai  }
23826516Sbrian
23936285Sbrian  bundle_DatalinkRemove(arg->bundle, arg->cx);
24036285Sbrian  return 0;
24136285Sbrian}
24232711Sbrian
24336285Sbrianstatic int
24436285SbrianRenameCommand(struct cmdargs const *arg)
24536285Sbrian{
24636285Sbrian  if (arg->argc != arg->argn + 1)
24736285Sbrian    return -1;
24831121Sbrian
24936285Sbrian  if (bundle_RenameDatalink(arg->bundle, arg->cx, arg->argv[arg->argn]))
25036285Sbrian    return 0;
25136285Sbrian
25236285Sbrian  log_Printf(LogWARN, "%s -> %s: target name already exists\n",
25336285Sbrian             arg->cx->name, arg->argv[arg->argn]);
25436285Sbrian  return 1;
25536285Sbrian}
25636285Sbrian
25736285Sbrianint
25836285SbrianLoadCommand(struct cmdargs const *arg)
25936285Sbrian{
26036285Sbrian  const char *name;
26136285Sbrian
26236285Sbrian  if (arg->argc > arg->argn)
26336285Sbrian    name = arg->argv[arg->argn];
26436285Sbrian  else
26536285Sbrian    name = "default";
26636285Sbrian
26736928Sbrian  if (!system_IsValid(name, arg->prompt, arg->bundle->phys_type.all)) {
26837019Sbrian    log_Printf(LogWARN, "%s: Label not allowed\n", name);
26936285Sbrian    return 1;
27036285Sbrian  } else {
27136285Sbrian    /*
27236285Sbrian     * Set the label before & after so that `set enddisc' works and
27336285Sbrian     * we handle nested `load' commands.
27436285Sbrian     */
27536285Sbrian    bundle_SetLabel(arg->bundle, arg->argc > arg->argn ? name : NULL);
27637008Sbrian    if (system_Select(arg->bundle, name, CONFFILE, arg->prompt, arg->cx) < 0) {
27736285Sbrian      bundle_SetLabel(arg->bundle, NULL);
27836285Sbrian      log_Printf(LogWARN, "%s: label not found.\n", name);
27936285Sbrian      return -1;
28032403Sbrian    }
28136285Sbrian    bundle_SetLabel(arg->bundle, arg->argc > arg->argn ? name : NULL);
28236285Sbrian  }
28326516Sbrian  return 0;
2846059Samurai}
2856059Samurai
28636285Sbrianint
28736285SbrianSaveCommand(struct cmdargs const *arg)
28836285Sbrian{
28936285Sbrian  log_Printf(LogWARN, "save command is not implemented (yet).\n");
29036285Sbrian  return 1;
29136285Sbrian}
29236285Sbrian
29310528Samuraistatic int
29436285SbrianDialCommand(struct cmdargs const *arg)
29528536Sbrian{
29636285Sbrian  int res;
29736285Sbrian
29836465Sbrian  if ((arg->cx && !(arg->cx->physical->type & (PHYS_INTERACTIVE|PHYS_AUTO)))
29936465Sbrian      || (!arg->cx &&
30036928Sbrian          (arg->bundle->phys_type.all & ~(PHYS_INTERACTIVE|PHYS_AUTO)))) {
30136285Sbrian    log_Printf(LogWARN, "Manual dial is only available for auto and"
30236285Sbrian              " interactive links\n");
30336285Sbrian    return 1;
30434536Sbrian  }
30536285Sbrian
30636285Sbrian  if (arg->argc > arg->argn && (res = LoadCommand(arg)) != 0)
30736285Sbrian    return res;
30836285Sbrian
30936285Sbrian  bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL);
31036285Sbrian
31136285Sbrian  return 0;
31228536Sbrian}
31328536Sbrian
31428536Sbrianstatic int
31531343SbrianShellCommand(struct cmdargs const *arg, int bg)
31610528Samurai{
31710528Samurai  const char *shell;
31810528Samurai  pid_t shpid;
31931343Sbrian  int argc;
32031343Sbrian  char *argv[MAXARGS];
32120813Sjkh
32218856Ssos#ifdef SHELL_ONLY_INTERACTIVELY
32326911Sbrian  /* we're only allowed to shell when we run ppp interactively */
32436285Sbrian  if (arg->prompt && arg->prompt->owner) {
32536285Sbrian    log_Printf(LogWARN, "Can't start a shell from a network connection\n");
32626516Sbrian    return 1;
32710528Samurai  }
32826911Sbrian#endif
32928679Sbrian
33036285Sbrian  if (arg->argc == arg->argn) {
33136285Sbrian    if (!arg->prompt) {
33236285Sbrian      log_Printf(LogWARN, "Can't start an interactive shell from"
33336285Sbrian                " a config file\n");
33428381Sbrian      return 1;
33536285Sbrian    } else if (arg->prompt->owner) {
33636285Sbrian      log_Printf(LogWARN, "Can't start an interactive shell from"
33736285Sbrian                " a socket connection\n");
33836285Sbrian      return 1;
33928381Sbrian    } else if (bg) {
34036285Sbrian      log_Printf(LogWARN, "Can only start an interactive shell in"
34128679Sbrian		" the foreground mode\n");
34228381Sbrian      return 1;
34328381Sbrian    }
34434536Sbrian  }
34534536Sbrian
34628679Sbrian  if ((shpid = fork()) == 0) {
34736285Sbrian    int i, fd;
34818531Sbde
34936285Sbrian    if ((shell = getenv("SHELL")) == 0)
35036285Sbrian      shell = _PATH_BSHELL;
35132017Sbrian
35236285Sbrian    timer_TermService();
35336285Sbrian
35436285Sbrian    if (arg->prompt)
35536285Sbrian      fd = arg->prompt->fd_out;
35636285Sbrian    else if ((fd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
35736285Sbrian      log_Printf(LogALERT, "Failed to open %s: %s\n",
35836285Sbrian                _PATH_DEVNULL, strerror(errno));
35928679Sbrian      exit(1);
36028679Sbrian    }
36128679Sbrian    for (i = 0; i < 3; i++)
36228679Sbrian      dup2(fd, i);
36326516Sbrian
36436285Sbrian    fcntl(3, F_SETFD, 1);	/* Set close-on-exec flag */
36526516Sbrian
36631061Sbrian    setuid(geteuid());
36736285Sbrian    if (arg->argc > arg->argn) {
36828679Sbrian      /* substitute pseudo args */
36936285Sbrian      argv[0] = strdup(arg->argv[arg->argn]);
37036285Sbrian      for (argc = 1; argc < arg->argc - arg->argn; argc++) {
37136285Sbrian	if (strcasecmp(arg->argv[argc + arg->argn], "HISADDR") == 0)
37236285Sbrian	  argv[argc] = strdup(inet_ntoa(arg->bundle->ncp.ipcp.peer_ip));
37336285Sbrian	else if (strcasecmp(arg->argv[argc + arg->argn], "INTERFACE") == 0)
37436285Sbrian	  argv[argc] = strdup(arg->bundle->ifp.Name);
37536285Sbrian	else if (strcasecmp(arg->argv[argc + arg->argn], "MYADDR") == 0)
37636285Sbrian	  argv[argc] = strdup(inet_ntoa(arg->bundle->ncp.ipcp.my_ip));
37731343Sbrian        else
37836285Sbrian          argv[argc] = strdup(arg->argv[argc + arg->argn]);
37931343Sbrian      }
38031343Sbrian      argv[argc] = NULL;
38128679Sbrian      if (bg) {
38228679Sbrian	pid_t p;
38310528Samurai
38428679Sbrian	p = getpid();
38528679Sbrian	if (daemon(1, 1) == -1) {
38636832Sbrian	  log_Printf(LogERROR, "%d: daemon: %s\n", (int)p, strerror(errno));
38728679Sbrian	  exit(1);
38828679Sbrian	}
38936285Sbrian      } else if (arg->prompt)
39036285Sbrian        printf("ppp: Pausing until %s finishes\n", arg->argv[arg->argn]);
39131343Sbrian      execvp(argv[0], argv);
39230316Sbrian    } else {
39336285Sbrian      if (arg->prompt)
39432017Sbrian        printf("ppp: Pausing until %s finishes\n", shell);
39536285Sbrian      prompt_TtyOldMode(arg->prompt);
39631343Sbrian      execl(shell, shell, NULL);
39730316Sbrian    }
39820813Sjkh
39936285Sbrian    log_Printf(LogWARN, "exec() of %s failed\n",
40036285Sbrian              arg->argc > arg->argn ? arg->argv[arg->argn] : shell);
40128679Sbrian    exit(255);
40210528Samurai  }
40336285Sbrian
40436285Sbrian  if (shpid == (pid_t) - 1)
40536285Sbrian    log_Printf(LogERROR, "Fork failed: %s\n", strerror(errno));
40636285Sbrian  else {
40710528Samurai    int status;
40831343Sbrian    waitpid(shpid, &status, 0);
40910528Samurai  }
41020813Sjkh
41136285Sbrian  if (arg->prompt && !arg->prompt->owner)
41236285Sbrian    prompt_TtyCommandMode(arg->prompt);
41320813Sjkh
41436285Sbrian  return 0;
41510528Samurai}
41610528Samurai
41731343Sbrianstatic int
41831343SbrianBgShellCommand(struct cmdargs const *arg)
41931343Sbrian{
42036285Sbrian  if (arg->argc == arg->argn)
42131343Sbrian    return -1;
42231343Sbrian  return ShellCommand(arg, 1);
42331343Sbrian}
42431343Sbrian
42531343Sbrianstatic int
42631343SbrianFgShellCommand(struct cmdargs const *arg)
42731343Sbrian{
42831343Sbrian  return ShellCommand(arg, 0);
42931343Sbrian}
43031343Sbrian
43130715Sbrianstatic struct cmdtab const Commands[] = {
43236285Sbrian  {"accept", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
43328679Sbrian  "accept option request", "accept option .."},
43428679Sbrian  {"add", NULL, AddCommand, LOCAL_AUTH,
43532109Sbrian  "add route", "add dest mask gateway", NULL},
43636285Sbrian  {NULL, "add!", AddCommand, LOCAL_AUTH,
43732109Sbrian  "add or change route", "add! dest mask gateway", (void *)1},
43836285Sbrian#ifndef NOALIAS
43936285Sbrian  {"alias", NULL, AliasCommand, LOCAL_AUTH,
44036285Sbrian  "alias control", "alias option [yes|no]"},
44136285Sbrian#endif
44231121Sbrian  {"allow", "auth", AllowCommand, LOCAL_AUTH,
44331121Sbrian  "Allow ppp access", "allow users|modes ...."},
44428679Sbrian  {"bg", "!bg", BgShellCommand, LOCAL_AUTH,
44531372Sbrian  "Run a background command", "[!]bg command"},
44636934Sbrian  {"clear", NULL, ClearCommand, LOCAL_AUTH | LOCAL_CX_OPT,
44736934Sbrian  "Clear throughput statistics", "clear ipcp|modem [current|overall|peak]..."},
44836285Sbrian  {"clone", NULL, CloneCommand, LOCAL_AUTH | LOCAL_CX,
44936285Sbrian  "Clone a link", "clone newname..."},
45036285Sbrian  {"close", NULL, CloseCommand, LOCAL_AUTH | LOCAL_CX_OPT,
45136285Sbrian  "Close an FSM", "close [lcp|ccp]"},
45228679Sbrian  {"delete", NULL, DeleteCommand, LOCAL_AUTH,
45332109Sbrian  "delete route", "delete dest", NULL},
45436285Sbrian  {NULL, "delete!", DeleteCommand, LOCAL_AUTH,
45532109Sbrian  "delete a route if it exists", "delete! dest", (void *)1},
45636285Sbrian  {"deny", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
45728679Sbrian  "Deny option request", "deny option .."},
45836285Sbrian  {"dial", "call", DialCommand, LOCAL_AUTH | LOCAL_CX_OPT,
45928679Sbrian  "Dial and login", "dial|call [remote]"},
46036285Sbrian  {"disable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
46128679Sbrian  "Disable option", "disable option .."},
46236285Sbrian  {"down", NULL, DownCommand, LOCAL_AUTH | LOCAL_CX_OPT,
46336285Sbrian  "Generate a down event", "down"},
46436285Sbrian  {"enable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
46528679Sbrian  "Enable option", "enable option .."},
46636285Sbrian  {"link", "datalink", LinkCommand, LOCAL_AUTH,
46736285Sbrian  "Link specific commands", "link name command ..."},
46837008Sbrian  {"load", NULL, LoadCommand, LOCAL_AUTH | LOCAL_CX_OPT,
46928679Sbrian  "Load settings", "load [remote]"},
47036285Sbrian  {"open", NULL, OpenCommand, LOCAL_AUTH | LOCAL_CX_OPT,
47137160Sbrian  "Open an FSM", "open [lcp|ccp|ipcp]"},
47236285Sbrian  {"passwd", NULL, PasswdCommand, LOCAL_NO_AUTH,
47336285Sbrian  "Password for manipulation", "passwd LocalPassword"},
47436285Sbrian  {"quit", "bye", QuitCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
47536285Sbrian  "Quit PPP program", "quit|bye [all]"},
47636285Sbrian  {"remove", "rm", RemoveCommand, LOCAL_AUTH | LOCAL_CX,
47736285Sbrian  "Remove a link", "remove"},
47836285Sbrian  {"rename", "mv", RenameCommand, LOCAL_AUTH | LOCAL_CX,
47936285Sbrian  "Rename a link", "rename name"},
48028679Sbrian  {"save", NULL, SaveCommand, LOCAL_AUTH,
48128679Sbrian  "Save settings", "save"},
48236285Sbrian  {"set", "setup", SetCommand, LOCAL_AUTH | LOCAL_CX_OPT,
48328679Sbrian  "Set parameters", "set[up] var value"},
48428679Sbrian  {"shell", "!", FgShellCommand, LOCAL_AUTH,
48528679Sbrian  "Run a subshell", "shell|! [sh command]"},
48636285Sbrian  {"show", NULL, ShowCommand, LOCAL_AUTH | LOCAL_CX_OPT,
48731372Sbrian  "Show status and stats", "show var"},
48836285Sbrian  {"term", NULL, TerminalCommand, LOCAL_AUTH | LOCAL_CX,
48931372Sbrian  "Enter terminal mode", "term"},
49028679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
49131343Sbrian  "Display this message", "help|? [command]", Commands},
49228679Sbrian  {NULL, NULL, NULL},
4936059Samurai};
4946059Samurai
49528536Sbrianstatic int
49631343SbrianShowEscape(struct cmdargs const *arg)
4976059Samurai{
49836285Sbrian  if (arg->cx->physical->async.cfg.EscMap[32]) {
49936285Sbrian    int code, bit;
50036285Sbrian    const char *sep = "";
5016059Samurai
50226516Sbrian    for (code = 0; code < 32; code++)
50336285Sbrian      if (arg->cx->physical->async.cfg.EscMap[code])
50428679Sbrian	for (bit = 0; bit < 8; bit++)
50536285Sbrian	  if (arg->cx->physical->async.cfg.EscMap[code] & (1 << bit)) {
50636285Sbrian	    prompt_Printf(arg->prompt, "%s0x%02x", sep, (code << 3) + bit);
50736285Sbrian            sep = ", ";
50836285Sbrian          }
50936285Sbrian    prompt_Printf(arg->prompt, "\n");
5106059Samurai  }
51131077Sbrian  return 0;
5126059Samurai}
5136059Samurai
51428679Sbrianstatic int
51536285SbrianShowTimerList(struct cmdargs const *arg)
5166059Samurai{
51736285Sbrian  timer_Show(0, arg->prompt);
51831077Sbrian  return 0;
5196059Samurai}
5206059Samurai
52128679Sbrianstatic int
52231343SbrianShowStopped(struct cmdargs const *arg)
52328327Sbrian{
52436285Sbrian  prompt_Printf(arg->prompt, " Stopped Timer:  LCP: ");
52536285Sbrian  if (!arg->cx->physical->link.lcp.fsm.StoppedTimer.load)
52636285Sbrian    prompt_Printf(arg->prompt, "Disabled");
52728327Sbrian  else
52836285Sbrian    prompt_Printf(arg->prompt, "%ld secs",
52936285Sbrian                  arg->cx->physical->link.lcp.fsm.StoppedTimer.load / SECTICKS);
53028461Sbrian
53136285Sbrian  prompt_Printf(arg->prompt, ", CCP: ");
53236285Sbrian  if (!arg->cx->physical->link.ccp.fsm.StoppedTimer.load)
53336285Sbrian    prompt_Printf(arg->prompt, "Disabled");
53428461Sbrian  else
53536285Sbrian    prompt_Printf(arg->prompt, "%ld secs",
53636285Sbrian                  arg->cx->physical->link.ccp.fsm.StoppedTimer.load / SECTICKS);
53728461Sbrian
53836285Sbrian  prompt_Printf(arg->prompt, "\n");
53928461Sbrian
54031077Sbrian  return 0;
54128327Sbrian}
54228327Sbrian
54328679Sbrianstatic int
54431343SbrianShowVersion(struct cmdargs const *arg)
5456059Samurai{
54636285Sbrian  prompt_Printf(arg->prompt, "PPP Version %s - %s\n", Version, VersionDate);
54731077Sbrian  return 0;
5486059Samurai}
5496059Samurai
55028679Sbrianstatic int
55136285SbrianShowProtocolStats(struct cmdargs const *arg)
55226326Sbrian{
55336285Sbrian  struct link *l = command_ChooseLink(arg);
55426326Sbrian
55536285Sbrian  prompt_Printf(arg->prompt, "%s:\n", l->name);
55636285Sbrian  link_ReportProtocolStatus(l, arg->prompt);
55731077Sbrian  return 0;
55826326Sbrian}
55926326Sbrian
56030715Sbrianstatic struct cmdtab const ShowCommands[] = {
56136285Sbrian  {"bundle", NULL, bundle_ShowStatus, LOCAL_AUTH,
56236285Sbrian  "bundle details", "show bundle"},
56336285Sbrian  {"ccp", NULL, ccp_ReportStatus, LOCAL_AUTH | LOCAL_CX_OPT,
56436285Sbrian  "CCP status", "show cpp"},
56536285Sbrian  {"compress", NULL, sl_Show, LOCAL_AUTH,
56636285Sbrian  "VJ compression stats", "show compress"},
56736285Sbrian  {"escape", NULL, ShowEscape, LOCAL_AUTH | LOCAL_CX,
56836285Sbrian  "escape characters", "show escape"},
56936285Sbrian  {"filter", NULL, filter_Show, LOCAL_AUTH,
57036285Sbrian  "packet filters", "show filter [in|out|dial|alive]"},
57136285Sbrian  {"hdlc", NULL, hdlc_ReportStatus, LOCAL_AUTH | LOCAL_CX,
57236285Sbrian  "HDLC errors", "show hdlc"},
57336285Sbrian  {"ipcp", NULL, ipcp_Show, LOCAL_AUTH,
57436285Sbrian  "IPCP status", "show ipcp"},
57536285Sbrian  {"lcp", NULL, lcp_ReportStatus, LOCAL_AUTH | LOCAL_CX,
57636285Sbrian  "LCP status", "show lcp"},
57736285Sbrian  {"link", "datalink", datalink_Show, LOCAL_AUTH | LOCAL_CX,
57836285Sbrian  "(high-level) link info", "show link"},
57936285Sbrian  {"links", NULL, bundle_ShowLinks, LOCAL_AUTH,
58036285Sbrian  "available link names", "show links"},
58136285Sbrian  {"log", NULL, log_ShowLevel, LOCAL_AUTH,
58236285Sbrian  "log levels", "show log"},
58336285Sbrian  {"mem", NULL, mbuf_Show, LOCAL_AUTH,
58436285Sbrian  "mbuf allocations", "show mem"},
58536285Sbrian  {"modem", NULL, modem_ShowStatus, LOCAL_AUTH | LOCAL_CX,
58636285Sbrian  "(low-level) link info", "show modem"},
58736285Sbrian  {"mp", "multilink", mp_ShowStatus, LOCAL_AUTH,
58836285Sbrian  "multilink setup", "show mp"},
58936285Sbrian  {"proto", NULL, ShowProtocolStats, LOCAL_AUTH | LOCAL_CX_OPT,
59036285Sbrian  "protocol summary", "show proto"},
59136285Sbrian  {"route", NULL, route_Show, LOCAL_AUTH,
59236285Sbrian  "routing table", "show route"},
59336285Sbrian  {"stopped", NULL, ShowStopped, LOCAL_AUTH | LOCAL_CX,
59436285Sbrian  "STOPPED timeout", "show stopped"},
59536285Sbrian  {"timers", NULL, ShowTimerList, LOCAL_AUTH,
59636285Sbrian  "alarm timers", "show timers"},
59728679Sbrian  {"version", NULL, ShowVersion, LOCAL_NO_AUTH | LOCAL_AUTH,
59836285Sbrian  "version string", "show version"},
59936285Sbrian  {"who", NULL, log_ShowWho, LOCAL_AUTH,
60036285Sbrian  "client list", "show who"},
60128679Sbrian  {"help", "?", HelpCommand, LOCAL_NO_AUTH | LOCAL_AUTH,
60231343Sbrian  "Display this message", "show help|? [command]", ShowCommands},
60328679Sbrian  {NULL, NULL, NULL},
6046059Samurai};
6056059Samurai
60630715Sbrianstatic struct cmdtab const *
60731343SbrianFindCommand(struct cmdtab const *cmds, const char *str, int *pmatch)
6086059Samurai{
60926516Sbrian  int nmatch;
61026516Sbrian  int len;
61128679Sbrian  struct cmdtab const *found;
6126059Samurai
61326516Sbrian  found = NULL;
61426516Sbrian  len = strlen(str);
61526516Sbrian  nmatch = 0;
6166059Samurai  while (cmds->func) {
61725566Sbrian    if (cmds->name && strncasecmp(str, cmds->name, len) == 0) {
61826516Sbrian      if (cmds->name[len] == '\0') {
61928679Sbrian	*pmatch = 1;
62028679Sbrian	return cmds;
62126516Sbrian      }
6226059Samurai      nmatch++;
6236059Samurai      found = cmds;
62428679Sbrian    } else if (cmds->alias && strncasecmp(str, cmds->alias, len) == 0) {
62526516Sbrian      if (cmds->alias[len] == '\0') {
62628679Sbrian	*pmatch = 1;
62728679Sbrian	return cmds;
62826516Sbrian      }
6296059Samurai      nmatch++;
6306059Samurai      found = cmds;
6316059Samurai    }
6326059Samurai    cmds++;
6336059Samurai  }
6346059Samurai  *pmatch = nmatch;
63526516Sbrian  return found;
6366059Samurai}
6376059Samurai
63836285Sbrianstatic const char *
63936285SbrianmkPrefix(int argc, char const *const *argv, char *tgt, int sz)
64036285Sbrian{
64136285Sbrian  int f, tlen, len;
64236285Sbrian
64336285Sbrian  tlen = 0;
64436285Sbrian  for (f = 0; f < argc && tlen < sz - 2; f++) {
64536285Sbrian    if (f)
64636285Sbrian      tgt[tlen++] = ' ';
64736285Sbrian    len = strlen(argv[f]);
64836285Sbrian    if (len > sz - tlen - 1)
64936285Sbrian      len = sz - tlen - 1;
65036285Sbrian    strncpy(tgt+tlen, argv[f], len);
65136285Sbrian    tlen += len;
65236285Sbrian  }
65336285Sbrian  tgt[tlen] = '\0';
65436285Sbrian  return tgt;
65536285Sbrian}
65636285Sbrian
65730715Sbrianstatic int
65836285SbrianFindExec(struct bundle *bundle, struct cmdtab const *cmds, int argc, int argn,
65936285Sbrian         char const *const *argv, struct prompt *prompt, struct datalink *cx)
6606059Samurai{
66128679Sbrian  struct cmdtab const *cmd;
6626059Samurai  int val = 1;
6636059Samurai  int nmatch;
66431343Sbrian  struct cmdargs arg;
66536285Sbrian  char prefix[100];
6666059Samurai
66736285Sbrian  cmd = FindCommand(cmds, argv[argn], &nmatch);
6686059Samurai  if (nmatch > 1)
66936285Sbrian    log_Printf(LogWARN, "%s: Ambiguous command\n",
67036285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix));
67136285Sbrian  else if (cmd && (!prompt || (cmd->lauth & prompt->auth))) {
67236285Sbrian    if ((cmd->lauth & LOCAL_CX) && !cx)
67336285Sbrian      /* We've got no context, but we require it */
67436285Sbrian      cx = bundle2datalink(bundle, NULL);
67536285Sbrian
67636285Sbrian    if ((cmd->lauth & LOCAL_CX) && !cx)
67736285Sbrian      log_Printf(LogWARN, "%s: No context (use the `link' command)\n",
67836285Sbrian                mkPrefix(argn+1, argv, prefix, sizeof prefix));
67936285Sbrian    else {
68036285Sbrian      if (cx && !(cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
68136285Sbrian        log_Printf(LogWARN, "%s: Redundant context (%s) ignored\n",
68236285Sbrian                  mkPrefix(argn+1, argv, prefix, sizeof prefix), cx->name);
68336285Sbrian        cx = NULL;
68436285Sbrian      }
68536285Sbrian      arg.cmdtab = cmds;
68636285Sbrian      arg.cmd = cmd;
68736285Sbrian      arg.argc = argc;
68836285Sbrian      arg.argn = argn+1;
68936285Sbrian      arg.argv = argv;
69036285Sbrian      arg.bundle = bundle;
69136285Sbrian      arg.cx = cx;
69236285Sbrian      arg.prompt = prompt;
69336285Sbrian      val = (*cmd->func) (&arg);
69436285Sbrian    }
69531343Sbrian  } else
69636285Sbrian    log_Printf(LogWARN, "%s: Invalid command\n",
69736285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix));
69826516Sbrian
69926516Sbrian  if (val == -1)
70036285Sbrian    log_Printf(LogWARN, "Usage: %s\n", cmd->syntax);
70128679Sbrian  else if (val)
70236285Sbrian    log_Printf(LogWARN, "%s: Failed %d\n",
70336285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix), val);
70426516Sbrian
70526516Sbrian  return val;
7066059Samurai}
7076059Samurai
70837009Sbrianint
70937009Sbriancommand_Interpret(char *buff, int nb, char *argv[MAXARGS])
7106059Samurai{
7116059Samurai  char *cp;
7126059Samurai
7136059Samurai  if (nb > 0) {
7146059Samurai    cp = buff + strcspn(buff, "\r\n");
7156059Samurai    if (cp)
7166059Samurai      *cp = '\0';
71737009Sbrian    return MakeArgs(buff, argv, MAXARGS);
71837009Sbrian  }
71937009Sbrian  return 0;
72031121Sbrian}
7216059Samurai
72231822Sbrianstatic int
72331822Sbrianarghidden(int argc, char const *const *argv, int n)
72431822Sbrian{
72531822Sbrian  /* Is arg n of the given command to be hidden from the log ? */
72631828Sbrian
72731828Sbrian  /* set authkey xxxxx */
72831828Sbrian  /* set key xxxxx */
72931822Sbrian  if (n == 2 && !strncasecmp(argv[0], "se", 2) &&
73031822Sbrian      (!strncasecmp(argv[1], "authk", 5) || !strncasecmp(argv[1], "ke", 2)))
73131822Sbrian    return 1;
73231822Sbrian
73331828Sbrian  /* passwd xxxxx */
73431828Sbrian  if (n == 1 && !strncasecmp(argv[0], "p", 1))
73531828Sbrian    return 1;
73631828Sbrian
73736285Sbrian  /* set server port xxxxx .... */
73836285Sbrian  if (n == 3 && !strncasecmp(argv[0], "se", 2) &&
73936285Sbrian      !strncasecmp(argv[1], "se", 2))
74036285Sbrian    return 1;
74136285Sbrian
74231822Sbrian  return 0;
74331822Sbrian}
74431822Sbrian
74531121Sbrianvoid
74636285Sbriancommand_Run(struct bundle *bundle, int argc, char const *const *argv,
74737008Sbrian           struct prompt *prompt, const char *label, struct datalink *cx)
74831121Sbrian{
74931156Sbrian  if (argc > 0) {
75036285Sbrian    if (log_IsKept(LogCOMMAND)) {
75131156Sbrian      static char buf[LINE_LEN];
75231156Sbrian      int f, n;
75331156Sbrian
75431156Sbrian      *buf = '\0';
75531156Sbrian      if (label) {
75631962Sbrian        strncpy(buf, label, sizeof buf - 3);
75731962Sbrian        buf[sizeof buf - 3] = '\0';
75831156Sbrian        strcat(buf, ": ");
75931156Sbrian      }
76031156Sbrian      n = strlen(buf);
76131156Sbrian      for (f = 0; f < argc; f++) {
76231962Sbrian        if (n < sizeof buf - 1 && f)
76331156Sbrian          buf[n++] = ' ';
76431822Sbrian        if (arghidden(argc, argv, f))
76536285Sbrian          strncpy(buf+n, "********", sizeof buf - n - 1);
76631822Sbrian        else
76731962Sbrian          strncpy(buf+n, argv[f], sizeof buf - n - 1);
76831156Sbrian        n += strlen(buf+n);
76931156Sbrian      }
77036285Sbrian      log_Printf(LogCOMMAND, "%s\n", buf);
77131156Sbrian    }
77237008Sbrian    FindExec(bundle, Commands, argc, 0, argv, prompt, cx);
77331156Sbrian  }
7746059Samurai}
7756059Samurai
77631121Sbrianvoid
77736285Sbriancommand_Decode(struct bundle *bundle, char *buff, int nb, struct prompt *prompt,
77836285Sbrian              const char *label)
77931121Sbrian{
78031121Sbrian  int argc;
78137009Sbrian  char *argv[MAXARGS];
78231121Sbrian
78337009Sbrian  argc = command_Interpret(buff, nb, argv);
78437008Sbrian  command_Run(bundle, argc, (char const *const *)argv, prompt, label, NULL);
78531121Sbrian}
78631121Sbrian
7876059Samuraistatic int
78831343SbrianShowCommand(struct cmdargs const *arg)
7896059Samurai{
79036285Sbrian  if (!arg->prompt)
79136285Sbrian    log_Printf(LogWARN, "show: Cannot show without a prompt\n");
79236285Sbrian  else if (arg->argc > arg->argn)
79336285Sbrian    FindExec(arg->bundle, ShowCommands, arg->argc, arg->argn, arg->argv,
79436285Sbrian             arg->prompt, arg->cx);
7956059Samurai  else
79636285Sbrian    prompt_Printf(arg->prompt, "Use ``show ?'' to get a list.\n");
79726516Sbrian
79826516Sbrian  return 0;
7996059Samurai}
8006059Samurai
8016059Samuraistatic int
80231343SbrianTerminalCommand(struct cmdargs const *arg)
8036059Samurai{
80436285Sbrian  if (!arg->prompt) {
80536285Sbrian    log_Printf(LogWARN, "term: Need a prompt\n");
80626516Sbrian    return 1;
8076059Samurai  }
80836285Sbrian
80936285Sbrian  if (arg->cx->physical->link.lcp.fsm.state > ST_CLOSED) {
81036285Sbrian    prompt_Printf(arg->prompt, "LCP state is [%s]\n",
81136285Sbrian                  State2Nam(arg->cx->physical->link.lcp.fsm.state));
81236285Sbrian    return 1;
8136059Samurai  }
81436285Sbrian
81536285Sbrian  datalink_Up(arg->cx, 0, 0);
81636285Sbrian  prompt_TtyTermMode(arg->prompt, arg->cx);
81736285Sbrian  return 0;
8186059Samurai}
8196059Samurai
8206059Samuraistatic int
82131343SbrianQuitCommand(struct cmdargs const *arg)
8226059Samurai{
82336285Sbrian  if (!arg->prompt || prompt_IsController(arg->prompt) ||
82436285Sbrian      (arg->argc > arg->argn && !strcasecmp(arg->argv[arg->argn], "all") &&
82536285Sbrian       (arg->prompt->auth & LOCAL_AUTH)))
82636285Sbrian    Cleanup(EX_NORMAL);
82736285Sbrian  if (arg->prompt)
82836285Sbrian    prompt_Destroy(arg->prompt, 1);
82926516Sbrian
83026516Sbrian  return 0;
8316059Samurai}
8326059Samurai
8336059Samuraistatic int
83436285SbrianOpenCommand(struct cmdargs const *arg)
8356059Samurai{
83637160Sbrian  if (arg->argc == arg->argn)
83736285Sbrian    bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL);
83837160Sbrian  else if (arg->argc == arg->argn + 1) {
83937160Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp")) {
84037160Sbrian      if (arg->cx) {
84137160Sbrian        if (arg->cx->physical->link.lcp.fsm.state == ST_OPENED)
84237160Sbrian          fsm_Reopen(&arg->cx->physical->link.lcp.fsm);
84337160Sbrian        else
84437160Sbrian          bundle_Open(arg->bundle, arg->cx->name, PHYS_ALL);
84537160Sbrian      } else
84637160Sbrian        log_Printf(LogWARN, "open lcp: You must specify a link\n");
84737160Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) {
84837160Sbrian      struct fsm *fp;
8496059Samurai
85037210Sbrian      fp = &command_ChooseLink(arg)->ccp.fsm;
85137160Sbrian      if (fp->link->lcp.fsm.state != ST_OPENED)
85237160Sbrian        log_Printf(LogWARN, "open: LCP must be open before opening CCP\n");
85337160Sbrian      else if (fp->state == ST_OPENED)
85437160Sbrian        fsm_Reopen(fp);
85537160Sbrian      else {
85637160Sbrian        fp->open_mode = 0;	/* Not passive any more */
85737160Sbrian        if (fp->state == ST_STOPPED) {
85837160Sbrian          fsm_Down(fp);
85937160Sbrian          fsm_Up(fp);
86037160Sbrian        } else {
86137160Sbrian          fsm_Up(fp);
86237160Sbrian          fsm_Open(fp);
86337160Sbrian        }
86436285Sbrian      }
86537160Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ipcp")) {
86637160Sbrian      if (arg->cx)
86737160Sbrian        log_Printf(LogWARN, "open ipcp: You need not specify a link\n");
86837160Sbrian      if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED)
86937160Sbrian        fsm_Reopen(&arg->bundle->ncp.ipcp.fsm);
87037160Sbrian      else
87137160Sbrian        bundle_Open(arg->bundle, NULL, PHYS_ALL);
87237160Sbrian    } else
87337160Sbrian      return -1;
87436285Sbrian  } else
87536285Sbrian    return -1;
87636285Sbrian
87726516Sbrian  return 0;
8786059Samurai}
8796059Samurai
88025067Sbrianstatic int
88136285SbrianCloseCommand(struct cmdargs const *arg)
8826059Samurai{
88337007Sbrian  if (arg->argc == arg->argn)
88437007Sbrian    bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_STAYDOWN);
88537007Sbrian  else if (arg->argc == arg->argn + 1) {
88637007Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp"))
88737007Sbrian      bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_LCP);
88837007Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "ccp") ||
88937007Sbrian             !strcasecmp(arg->argv[arg->argn], "ccp!")) {
89037007Sbrian      struct fsm *fp;
8916059Samurai
89237210Sbrian      fp = &command_ChooseLink(arg)->ccp.fsm;
89337007Sbrian      if (fp->state == ST_OPENED) {
89437007Sbrian        fsm_Close(fp);
89537007Sbrian        if (arg->argv[arg->argn][3] == '!')
89637007Sbrian          fp->open_mode = 0;		/* Stay ST_CLOSED */
89737007Sbrian        else
89837007Sbrian          fp->open_mode = OPEN_PASSIVE;	/* Wait for the peer to start */
89937007Sbrian      }
90037007Sbrian    } else
90136285Sbrian      return -1;
90236285Sbrian  } else
90336285Sbrian    return -1;
90436285Sbrian
90536285Sbrian  return 0;
9066059Samurai}
9076059Samurai
90825067Sbrianstatic int
90936285SbrianDownCommand(struct cmdargs const *arg)
91011336Samurai{
91137018Sbrian  if (arg->argc == arg->argn) {
91237018Sbrian      if (arg->cx)
91337018Sbrian        datalink_Down(arg->cx, CLOSE_STAYDOWN);
91437018Sbrian      else
91537018Sbrian        bundle_Down(arg->bundle, CLOSE_STAYDOWN);
91637018Sbrian  } else if (arg->argc == arg->argn + 1) {
91737018Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp")) {
91837018Sbrian      if (arg->cx)
91937018Sbrian        datalink_Down(arg->cx, CLOSE_LCP);
92037018Sbrian      else
92137018Sbrian        bundle_Down(arg->bundle, CLOSE_LCP);
92237018Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) {
92337018Sbrian      struct fsm *fp = arg->cx ? &arg->cx->physical->link.ccp.fsm :
92437018Sbrian                                 &arg->bundle->ncp.mp.link.ccp.fsm;
92537060Sbrian      fsm2initial(fp);
92637018Sbrian    } else
92737018Sbrian      return -1;
92836285Sbrian  } else
92936285Sbrian    return -1;
93036285Sbrian
93136285Sbrian  return 0;
93225067Sbrian}
93325067Sbrian
93425067Sbrianstatic int
93536285SbrianSetModemSpeed(struct cmdargs const *arg)
93625067Sbrian{
93736285Sbrian  long speed;
93836285Sbrian  char *end;
93911336Samurai
94036285Sbrian  if (arg->argc > arg->argn && *arg->argv[arg->argn]) {
94136285Sbrian    if (arg->argc > arg->argn+1) {
94236285Sbrian      log_Printf(LogWARN, "SetModemSpeed: Too many arguments");
94336285Sbrian      return -1;
94411336Samurai    }
94536285Sbrian    if (strcasecmp(arg->argv[arg->argn], "sync") == 0) {
94636285Sbrian      physical_SetSync(arg->cx->physical);
94736285Sbrian      return 0;
94836285Sbrian    }
94936285Sbrian    end = NULL;
95036285Sbrian    speed = strtol(arg->argv[arg->argn], &end, 10);
95136285Sbrian    if (*end) {
95236285Sbrian      log_Printf(LogWARN, "SetModemSpeed: Bad argument \"%s\"",
95336285Sbrian                arg->argv[arg->argn]);
95436285Sbrian      return -1;
95536285Sbrian    }
95636285Sbrian    if (physical_SetSpeed(arg->cx->physical, speed))
95736285Sbrian      return 0;
95836285Sbrian    log_Printf(LogWARN, "%s: Invalid speed\n", arg->argv[arg->argn]);
95936285Sbrian  } else
96036285Sbrian    log_Printf(LogWARN, "SetModemSpeed: No speed specified\n");
96124939Sbrian
96226516Sbrian  return -1;
96311336Samurai}
96411336Samurai
96525067Sbrianstatic int
96631343SbrianSetStoppedTimeout(struct cmdargs const *arg)
96728327Sbrian{
96836285Sbrian  struct link *l = &arg->cx->physical->link;
96936285Sbrian
97036285Sbrian  l->lcp.fsm.StoppedTimer.load = 0;
97136285Sbrian  l->ccp.fsm.StoppedTimer.load = 0;
97236285Sbrian  if (arg->argc <= arg->argn+2) {
97336285Sbrian    if (arg->argc > arg->argn) {
97436285Sbrian      l->lcp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn]) * SECTICKS;
97536285Sbrian      if (arg->argc > arg->argn+1)
97636285Sbrian        l->ccp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn+1]) * SECTICKS;
97728461Sbrian    }
97828327Sbrian    return 0;
97928327Sbrian  }
98028327Sbrian  return -1;
98128327Sbrian}
98228327Sbrian
98331081Sbrian#define ismask(x) \
98431081Sbrian  (*x == '0' && strlen(x) == 4 && strspn(x+1, "0123456789.") == 3)
98531081Sbrian
98628327Sbrianstatic int
98731343SbrianSetServer(struct cmdargs const *arg)
98826940Sbrian{
98926940Sbrian  int res = -1;
99026940Sbrian
99136285Sbrian  if (arg->argc > arg->argn && arg->argc < arg->argn+4) {
99231081Sbrian    const char *port, *passwd, *mask;
99331081Sbrian
99431081Sbrian    /* What's what ? */
99536285Sbrian    port = arg->argv[arg->argn];
99636285Sbrian    if (arg->argc == arg->argn + 2) {
99736285Sbrian      passwd = arg->argv[arg->argn+1];
99836285Sbrian      mask = NULL;
99936285Sbrian    } else if (arg->argc == arg->argn + 3) {
100036285Sbrian      passwd = arg->argv[arg->argn+1];
100136285Sbrian      mask = arg->argv[arg->argn+2];
100231081Sbrian      if (!ismask(mask))
100331081Sbrian        return -1;
100436285Sbrian    } else if (strcasecmp(port, "none") == 0) {
100536285Sbrian      if (server_Close(arg->bundle))
100636285Sbrian        log_Printf(LogPHASE, "Disabled server port.\n");
100736285Sbrian      return 0;
100831081Sbrian    } else
100936285Sbrian      return -1;
101031081Sbrian
101136285Sbrian    strncpy(server.passwd, passwd, sizeof server.passwd - 1);
101236285Sbrian    server.passwd[sizeof server.passwd - 1] = '\0';
101331081Sbrian
101436285Sbrian    if (*port == '/') {
101531081Sbrian      mode_t imask;
101636285Sbrian      char *ptr, name[LINE_LEN + 12];
101728679Sbrian
101831081Sbrian      if (mask != NULL) {
101928679Sbrian	unsigned m;
102028679Sbrian
102131081Sbrian	if (sscanf(mask, "%o", &m) == 1)
102231081Sbrian	  imask = m;
102331081Sbrian        else
102431081Sbrian          return -1;
102531081Sbrian      } else
102631081Sbrian        imask = (mode_t)-1;
102736285Sbrian
102836285Sbrian      ptr = strstr(port, "%d");
102936285Sbrian      if (ptr) {
103036285Sbrian        snprintf(name, sizeof name, "%.*s%d%s",
103137210Sbrian                 (int)(ptr - port), port, arg->bundle->unit, ptr + 2);
103236285Sbrian        port = name;
103336285Sbrian      }
103436285Sbrian      res = server_LocalOpen(arg->bundle, port, imask);
103527346Sbrian    } else {
103636285Sbrian      int iport, add = 0;
103728679Sbrian
103831081Sbrian      if (mask != NULL)
103931081Sbrian        return -1;
104028679Sbrian
104136285Sbrian      if (*port == '+') {
104236285Sbrian        port++;
104336285Sbrian        add = 1;
104436285Sbrian      }
104531081Sbrian      if (strspn(port, "0123456789") != strlen(port)) {
104631081Sbrian        struct servent *s;
104731081Sbrian
104831081Sbrian        if ((s = getservbyname(port, "tcp")) == NULL) {
104931081Sbrian	  iport = 0;
105036285Sbrian	  log_Printf(LogWARN, "%s: Invalid port or service\n", port);
105128679Sbrian	} else
105231081Sbrian	  iport = ntohs(s->s_port);
105327346Sbrian      } else
105431081Sbrian        iport = atoi(port);
105536285Sbrian
105636285Sbrian      if (iport) {
105736285Sbrian        if (add)
105836285Sbrian          iport += arg->bundle->unit;
105936285Sbrian        res = server_TcpOpen(arg->bundle, iport);
106036285Sbrian      } else
106136285Sbrian        res = -1;
106227346Sbrian    }
106331081Sbrian  }
106426940Sbrian
106526940Sbrian  return res;
106626940Sbrian}
106726940Sbrian
106826940Sbrianstatic int
106931343SbrianSetModemParity(struct cmdargs const *arg)
10706059Samurai{
107136285Sbrian  return arg->argc > arg->argn ? modem_SetParity(arg->cx->physical,
107236285Sbrian                                                 arg->argv[arg->argn]) : -1;
10736059Samurai}
10746059Samurai
10756059Samuraistatic int
107631343SbrianSetEscape(struct cmdargs const *arg)
10776059Samurai{
10786059Samurai  int code;
107936285Sbrian  int argc = arg->argc - arg->argn;
108036285Sbrian  char const *const *argv = arg->argv + arg->argn;
10816059Samurai
10826059Samurai  for (code = 0; code < 33; code++)
108336285Sbrian    arg->cx->physical->async.cfg.EscMap[code] = 0;
108431343Sbrian
10856059Samurai  while (argc-- > 0) {
10866059Samurai    sscanf(*argv++, "%x", &code);
10876059Samurai    code &= 0xff;
108836285Sbrian    arg->cx->physical->async.cfg.EscMap[code >> 3] |= (1 << (code & 7));
108936285Sbrian    arg->cx->physical->async.cfg.EscMap[32] = 1;
10906059Samurai  }
109126516Sbrian  return 0;
10926059Samurai}
10936059Samurai
109430715Sbrianstatic struct in_addr
109531343SbrianGetIpAddr(const char *cp)
10966059Samurai{
10976059Samurai  struct hostent *hp;
10986059Samurai  struct in_addr ipaddr;
10996059Samurai
110032124Sbrian  if (inet_aton(cp, &ipaddr) == 0) {
110132124Sbrian    hp = gethostbyname(cp);
110232124Sbrian    if (hp && hp->h_addrtype == AF_INET)
110332124Sbrian      memcpy(&ipaddr, hp->h_addr, hp->h_length);
110432124Sbrian    else
110532124Sbrian      ipaddr.s_addr = 0;
110632124Sbrian  }
110728679Sbrian  return (ipaddr);
11086059Samurai}
11096059Samurai
11106059Samuraistatic int
111131343SbrianSetInterfaceAddr(struct cmdargs const *arg)
11126059Samurai{
111336285Sbrian  struct ipcp *ipcp = &arg->bundle->ncp.ipcp;
111432267Sbrian  const char *hisaddr;
111532267Sbrian
111632267Sbrian  hisaddr = NULL;
111736285Sbrian  ipcp->cfg.my_range.ipaddr.s_addr = INADDR_ANY;
111836285Sbrian  ipcp->cfg.peer_range.ipaddr.s_addr = INADDR_ANY;
11196059Samurai
112036285Sbrian  if (arg->argc > arg->argn + 4)
112128679Sbrian    return -1;
112226516Sbrian
112336285Sbrian  ipcp->cfg.HaveTriggerAddress = 0;
112436285Sbrian  ipcp->cfg.netmask.s_addr = INADDR_ANY;
112536285Sbrian  iplist_reset(&ipcp->cfg.peer_list);
112628394Sbrian
112736285Sbrian  if (arg->argc > arg->argn) {
112836285Sbrian    if (!ParseAddr(ipcp, arg->argc - arg->argn, arg->argv + arg->argn,
112936285Sbrian                   &ipcp->cfg.my_range.ipaddr, &ipcp->cfg.my_range.mask,
113036285Sbrian                   &ipcp->cfg.my_range.width))
113128679Sbrian      return 1;
113236285Sbrian    if (arg->argc > arg->argn+1) {
113336285Sbrian      hisaddr = arg->argv[arg->argn+1];
113436285Sbrian      if (arg->argc > arg->argn+2) {
113536285Sbrian        ipcp->cfg.netmask = GetIpAddr(arg->argv[arg->argn+2]);
113636285Sbrian	if (arg->argc > arg->argn+3) {
113736285Sbrian	  ipcp->cfg.TriggerAddress = GetIpAddr(arg->argv[arg->argn+3]);
113836285Sbrian	  ipcp->cfg.HaveTriggerAddress = 1;
11399440Samurai	}
11406059Samurai      }
11416059Samurai    }
11426059Samurai  }
114328394Sbrian
11446059Samurai  /*
11456059Samurai   * For backwards compatibility, 0.0.0.0 means any address.
11466059Samurai   */
114736285Sbrian  if (ipcp->cfg.my_range.ipaddr.s_addr == INADDR_ANY) {
114836285Sbrian    ipcp->cfg.my_range.mask.s_addr = INADDR_ANY;
114936285Sbrian    ipcp->cfg.my_range.width = 0;
11506059Samurai  }
115136285Sbrian  ipcp->my_ip.s_addr = ipcp->cfg.my_range.ipaddr.s_addr;
115236285Sbrian
115336285Sbrian  if (ipcp->cfg.peer_range.ipaddr.s_addr == INADDR_ANY) {
115436285Sbrian    ipcp->cfg.peer_range.mask.s_addr = INADDR_ANY;
115536285Sbrian    ipcp->cfg.peer_range.width = 0;
11566059Samurai  }
115728537Sbrian
115836285Sbrian  if (hisaddr && !ipcp_UseHisaddr(arg->bundle, hisaddr,
115936928Sbrian                                  arg->bundle->phys_type.all & PHYS_AUTO))
116032267Sbrian    return 4;
116131121Sbrian
116226516Sbrian  return 0;
11636059Samurai}
11646059Samurai
116518752Sjkhstatic int
116631343SbrianSetVariable(struct cmdargs const *arg)
11676059Samurai{
116837210Sbrian  long long_val, param = (long)arg->cmd->args;
116937210Sbrian  int mode, dummyint;
117031343Sbrian  const char *argp;
117136285Sbrian  struct datalink *cx = arg->cx;	/* LOCAL_CX uses this */
117236285Sbrian  const char *err = NULL;
117336285Sbrian  struct link *l = command_ChooseLink(arg);	/* LOCAL_CX_OPT uses this */
117436285Sbrian  struct in_addr dummyaddr, *addr;
11756059Samurai
117636285Sbrian  if (arg->argc > arg->argn)
117736285Sbrian    argp = arg->argv[arg->argn];
117826551Sbrian  else
117931343Sbrian    argp = "";
118026551Sbrian
118136285Sbrian  if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
118236285Sbrian    log_Printf(LogWARN, "set %s: No context (use the `link' command)\n",
118336285Sbrian              arg->cmd->name);
118436285Sbrian    return 1;
118536285Sbrian  } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
118636285Sbrian    log_Printf(LogWARN, "set %s: Redundant context (%s) ignored\n",
118736285Sbrian              arg->cmd->name, cx->name);
118836285Sbrian    cx = NULL;
118936285Sbrian  }
119036285Sbrian
119126551Sbrian  switch (param) {
119228679Sbrian  case VAR_AUTHKEY:
119336285Sbrian    if (bundle_Phase(arg->bundle) == PHASE_DEAD) {
119436285Sbrian      strncpy(arg->bundle->cfg.auth.key, argp,
119536285Sbrian              sizeof arg->bundle->cfg.auth.key - 1);
119636285Sbrian      arg->bundle->cfg.auth.key[sizeof arg->bundle->cfg.auth.key - 1] = '\0';
119736285Sbrian    } else {
119836285Sbrian      err = "set authkey: Only available at phase DEAD\n";
119936285Sbrian      log_Printf(LogWARN, err);
120036285Sbrian    }
120128679Sbrian    break;
120237210Sbrian
120328679Sbrian  case VAR_AUTHNAME:
120436285Sbrian    if (bundle_Phase(arg->bundle) == PHASE_DEAD) {
120536285Sbrian      strncpy(arg->bundle->cfg.auth.name, argp,
120636285Sbrian              sizeof arg->bundle->cfg.auth.name - 1);
120736285Sbrian      arg->bundle->cfg.auth.name[sizeof arg->bundle->cfg.auth.name - 1] = '\0';
120836285Sbrian    } else {
120936285Sbrian      err = "set authname: Only available at phase DEAD\n";
121036285Sbrian      log_Printf(LogWARN, err);
121136285Sbrian    }
121228679Sbrian    break;
121337210Sbrian
121436285Sbrian  case VAR_AUTOLOAD:
121536285Sbrian    if (arg->argc == arg->argn + 2 || arg->argc == arg->argn + 4) {
121636285Sbrian      arg->bundle->autoload.running = 1;
121736285Sbrian      arg->bundle->cfg.autoload.max.timeout = atoi(arg->argv[arg->argn]);
121836285Sbrian      arg->bundle->cfg.autoload.max.packets = atoi(arg->argv[arg->argn + 1]);
121936285Sbrian      if (arg->argc == arg->argn + 4) {
122036285Sbrian        arg->bundle->cfg.autoload.min.timeout = atoi(arg->argv[arg->argn + 2]);
122136285Sbrian        arg->bundle->cfg.autoload.min.packets = atoi(arg->argv[arg->argn + 3]);
122236285Sbrian      } else {
122336285Sbrian        arg->bundle->cfg.autoload.min.timeout = 0;
122436285Sbrian        arg->bundle->cfg.autoload.min.packets = 0;
122536285Sbrian      }
122636285Sbrian    } else {
122736285Sbrian      err = "Set autoload requires two or four arguments\n";
122836285Sbrian      log_Printf(LogWARN, err);
122936285Sbrian    }
123036285Sbrian    break;
123137210Sbrian
123228679Sbrian  case VAR_DIAL:
123336285Sbrian    strncpy(cx->cfg.script.dial, argp, sizeof cx->cfg.script.dial - 1);
123436285Sbrian    cx->cfg.script.dial[sizeof cx->cfg.script.dial - 1] = '\0';
123528679Sbrian    break;
123637210Sbrian
123728679Sbrian  case VAR_LOGIN:
123836285Sbrian    strncpy(cx->cfg.script.login, argp, sizeof cx->cfg.script.login - 1);
123936285Sbrian    cx->cfg.script.login[sizeof cx->cfg.script.login - 1] = '\0';
124028679Sbrian    break;
124137210Sbrian
124236285Sbrian  case VAR_WINSIZE:
124336285Sbrian    if (arg->argc > arg->argn) {
124436285Sbrian      l->ccp.cfg.deflate.out.winsize = atoi(arg->argv[arg->argn]);
124536285Sbrian      if (l->ccp.cfg.deflate.out.winsize < 8 ||
124636285Sbrian          l->ccp.cfg.deflate.out.winsize > 15) {
124736285Sbrian          log_Printf(LogWARN, "%d: Invalid outgoing window size\n",
124836285Sbrian                    l->ccp.cfg.deflate.out.winsize);
124936285Sbrian          l->ccp.cfg.deflate.out.winsize = 15;
125036285Sbrian      }
125136285Sbrian      if (arg->argc > arg->argn+1) {
125236285Sbrian        l->ccp.cfg.deflate.in.winsize = atoi(arg->argv[arg->argn+1]);
125336285Sbrian        if (l->ccp.cfg.deflate.in.winsize < 8 ||
125436285Sbrian            l->ccp.cfg.deflate.in.winsize > 15) {
125536285Sbrian            log_Printf(LogWARN, "%d: Invalid incoming window size\n",
125636285Sbrian                      l->ccp.cfg.deflate.in.winsize);
125736285Sbrian            l->ccp.cfg.deflate.in.winsize = 15;
125836285Sbrian        }
125936285Sbrian      } else
126036285Sbrian        l->ccp.cfg.deflate.in.winsize = 0;
126136285Sbrian    } else {
126236285Sbrian      err = "No window size specified\n";
126336285Sbrian      log_Printf(LogWARN, err);
126436285Sbrian    }
126536285Sbrian    break;
126637210Sbrian
126728679Sbrian  case VAR_DEVICE:
126836285Sbrian    physical_SetDeviceList(cx->physical, arg->argc - arg->argn,
126936285Sbrian                           arg->argv + arg->argn);
127036285Sbrian    break;
127137210Sbrian
127236285Sbrian  case VAR_ACCMAP:
127336285Sbrian    if (arg->argc > arg->argn) {
127437210Sbrian      u_long ulong_val;
127536285Sbrian      sscanf(argp, "%lx", &ulong_val);
127637210Sbrian      cx->physical->link.lcp.cfg.accmap = (u_int32_t)ulong_val;
127736285Sbrian    } else {
127836285Sbrian      err = "No accmap specified\n";
127936285Sbrian      log_Printf(LogWARN, err);
128036285Sbrian    }
128136285Sbrian    break;
128237210Sbrian
128336285Sbrian  case VAR_MODE:
128436285Sbrian    mode = Nam2mode(argp);
128536285Sbrian    if (mode == PHYS_NONE || mode == PHYS_ALL) {
128636285Sbrian      log_Printf(LogWARN, "%s: Invalid mode\n", argp);
128736285Sbrian      return -1;
128836285Sbrian    }
128936285Sbrian    bundle_SetMode(arg->bundle, cx, mode);
129036285Sbrian    break;
129137210Sbrian
129236285Sbrian  case VAR_MRRU:
129337210Sbrian    if (bundle_Phase(arg->bundle) != PHASE_DEAD) {
129436285Sbrian      log_Printf(LogWARN, "mrru: Only changable at phase DEAD\n");
129537210Sbrian      return 1;
129629696Sbrian    }
129737210Sbrian    long_val = atol(argp);
129837210Sbrian    if (long_val && long_val < MIN_MRU) {
129937210Sbrian      log_Printf(LogWARN, "MRRU %ld: too small - min %d\n", long_val, MIN_MRU);
130037210Sbrian      return 1;
130137210Sbrian    } else if (long_val > MAX_MRU) {
130237210Sbrian      log_Printf(LogWARN, "MRRU %ld: too big - max %d\n", long_val, MAX_MRU);
130337210Sbrian      return 1;
130437210Sbrian    } else
130537210Sbrian      arg->bundle->ncp.mp.cfg.mrru = long_val;
130628679Sbrian    break;
130737210Sbrian
130836285Sbrian  case VAR_MRU:
130937210Sbrian    long_val = atol(argp);
131037210Sbrian    if (long_val == 0)
131137210Sbrian      l->lcp.cfg.mru = DEF_MRU;
131237210Sbrian    else if (long_val < MIN_MRU) {
131337210Sbrian      log_Printf(LogWARN, "MRU %ld: too small - min %d\n", long_val, MIN_MRU);
131437210Sbrian      return 1;
131537210Sbrian    } else if (long_val > MAX_MRU) {
131637210Sbrian      log_Printf(LogWARN, "MRU %ld: too big - max %d\n", long_val, MAX_MRU);
131737210Sbrian      return 1;
131837210Sbrian    } else
131937210Sbrian      l->lcp.cfg.mru = long_val;
132028679Sbrian    break;
132137210Sbrian
132236285Sbrian  case VAR_MTU:
132337210Sbrian    long_val = atol(argp);
132437210Sbrian    if (long_val && long_val < MIN_MTU) {
132537210Sbrian      log_Printf(LogWARN, "MTU %ld: too small - min %d\n", long_val, MIN_MTU);
132637210Sbrian      return 1;
132737210Sbrian    } else if (long_val > MAX_MTU) {
132837210Sbrian      log_Printf(LogWARN, "MTU %ld: too big - max %d\n", long_val, MAX_MTU);
132937210Sbrian      return 1;
133037210Sbrian    } else
133137210Sbrian      arg->bundle->cfg.mtu = long_val;
133236285Sbrian    break;
133337210Sbrian
133436285Sbrian  case VAR_OPENMODE:
133536285Sbrian    if (strcasecmp(argp, "active") == 0)
133636285Sbrian      cx->physical->link.lcp.cfg.openmode = arg->argc > arg->argn+1 ?
133736285Sbrian        atoi(arg->argv[arg->argn+1]) : 1;
133836285Sbrian    else if (strcasecmp(argp, "passive") == 0)
133936285Sbrian      cx->physical->link.lcp.cfg.openmode = OPEN_PASSIVE;
134036285Sbrian    else {
134136285Sbrian      err = "%s: Invalid openmode\n";
134236285Sbrian      log_Printf(LogWARN, err, argp);
134336285Sbrian    }
134436285Sbrian    break;
134537210Sbrian
134628679Sbrian  case VAR_PHONE:
134736285Sbrian    strncpy(cx->cfg.phone.list, argp, sizeof cx->cfg.phone.list - 1);
134836285Sbrian    cx->cfg.phone.list[sizeof cx->cfg.phone.list - 1] = '\0';
134928679Sbrian    break;
135037210Sbrian
135128679Sbrian  case VAR_HANGUP:
135236285Sbrian    strncpy(cx->cfg.script.hangup, argp, sizeof cx->cfg.script.hangup - 1);
135336285Sbrian    cx->cfg.script.hangup[sizeof cx->cfg.script.hangup - 1] = '\0';
135428679Sbrian    break;
135537210Sbrian
135636285Sbrian  case VAR_IDLETIMEOUT:
135736285Sbrian    if (arg->argc > arg->argn+1)
135836285Sbrian      err = "Too many idle timeout values\n";
135936285Sbrian    else if (arg->argc == arg->argn+1)
136036285Sbrian      bundle_SetIdleTimer(arg->bundle, atoi(argp));
136136285Sbrian    if (err)
136236285Sbrian      log_Printf(LogWARN, err);
136329549Sbrian    break;
136437210Sbrian
136536285Sbrian  case VAR_LQRPERIOD:
136637210Sbrian    long_val = atol(argp);
136737210Sbrian    if (long_val < MIN_LQRPERIOD) {
136837210Sbrian      log_Printf(LogWARN, "%ld: Invalid lqr period - min %d\n",
136937210Sbrian                 long_val, MIN_LQRPERIOD);
137037210Sbrian      return 1;
137136285Sbrian    } else
137237210Sbrian      l->lcp.cfg.lqrperiod = long_val;
137336285Sbrian    break;
137437210Sbrian
137536285Sbrian  case VAR_LCPRETRY:
137637210Sbrian    long_val = atol(argp);
137737210Sbrian    if (long_val < MIN_FSMRETRY) {
137837210Sbrian      log_Printf(LogWARN, "%ld: Invalid LCP FSM retry period - min %d\n",
137937210Sbrian                 long_val, MIN_FSMRETRY);
138037210Sbrian      return 1;
138136285Sbrian    } else
138237210Sbrian      cx->physical->link.lcp.cfg.fsmretry = long_val;
138336285Sbrian    break;
138437210Sbrian
138536285Sbrian  case VAR_CHAPRETRY:
138637210Sbrian    long_val = atol(argp);
138737210Sbrian    if (long_val < MIN_FSMRETRY) {
138837210Sbrian      log_Printf(LogWARN, "%ld: Invalid CHAP FSM retry period - min %d\n",
138937210Sbrian                 long_val, MIN_FSMRETRY);
139037210Sbrian      return 1;
139136285Sbrian    } else
139237210Sbrian      cx->chap.auth.cfg.fsmretry = long_val;
139336285Sbrian    break;
139437210Sbrian
139536285Sbrian  case VAR_PAPRETRY:
139637210Sbrian    long_val = atol(argp);
139737210Sbrian    if (long_val < MIN_FSMRETRY) {
139837210Sbrian      log_Printf(LogWARN, "%ld: Invalid PAP FSM retry period - min %d\n",
139937210Sbrian                 long_val, MIN_FSMRETRY);
140037210Sbrian      return 1;
140136285Sbrian    } else
140237210Sbrian      cx->pap.cfg.fsmretry = long_val;
140336285Sbrian    break;
140437210Sbrian
140536285Sbrian  case VAR_CCPRETRY:
140637210Sbrian    long_val = atol(argp);
140737210Sbrian    if (long_val < MIN_FSMRETRY) {
140837210Sbrian      log_Printf(LogWARN, "%ld: Invalid CCP FSM retry period - min %d\n",
140937210Sbrian                 long_val, MIN_FSMRETRY);
141037210Sbrian      return 1;
141136285Sbrian    } else
141237210Sbrian      l->ccp.cfg.fsmretry = long_val;
141336285Sbrian    break;
141437210Sbrian
141536285Sbrian  case VAR_IPCPRETRY:
141637210Sbrian    long_val = atol(argp);
141737210Sbrian    if (long_val < MIN_FSMRETRY) {
141837210Sbrian      log_Printf(LogWARN, "%ld: Invalid IPCP FSM retry period - min %d\n",
141937210Sbrian                 long_val, MIN_FSMRETRY);
142037210Sbrian      return 1;
142136285Sbrian    } else
142237210Sbrian      arg->bundle->ncp.ipcp.cfg.fsmretry = long_val;
142336285Sbrian    break;
142437210Sbrian
142536285Sbrian  case VAR_NBNS:
142636285Sbrian  case VAR_DNS:
142736285Sbrian    if (param == VAR_DNS)
142836285Sbrian      addr = arg->bundle->ncp.ipcp.cfg.ns.dns;
142936285Sbrian    else
143036285Sbrian      addr = arg->bundle->ncp.ipcp.cfg.ns.nbns;
143136285Sbrian
143236285Sbrian    addr[0].s_addr = addr[1].s_addr = INADDR_ANY;
143336285Sbrian
143436285Sbrian    if (arg->argc > arg->argn) {
143536285Sbrian      ParseAddr(&arg->bundle->ncp.ipcp, 1, arg->argv + arg->argn,
143636285Sbrian                addr, &dummyaddr, &dummyint);
143736285Sbrian      if (arg->argc > arg->argn+1)
143836285Sbrian        ParseAddr(&arg->bundle->ncp.ipcp, 1, arg->argv + arg->argn + 1,
143936285Sbrian                  addr + 1, &dummyaddr, &dummyint);
144036285Sbrian
144136285Sbrian      if (addr[1].s_addr == INADDR_ANY)
144236285Sbrian        addr[1].s_addr = addr[0].s_addr;
144336285Sbrian      if (addr[0].s_addr == INADDR_ANY)
144436285Sbrian        addr[0].s_addr = addr[1].s_addr;
144536285Sbrian    }
144636285Sbrian    break;
14476059Samurai  }
144836285Sbrian
144936285Sbrian  return err ? 1 : 0;
14506059Samurai}
14516059Samurai
145228679Sbrianstatic int
145331343SbrianSetCtsRts(struct cmdargs const *arg)
145420812Sjkh{
145536285Sbrian  if (arg->argc == arg->argn+1) {
145636285Sbrian    if (strcmp(arg->argv[arg->argn], "on") == 0)
145736285Sbrian      physical_SetRtsCts(arg->cx->physical, 1);
145836285Sbrian    else if (strcmp(arg->argv[arg->argn], "off") == 0)
145936285Sbrian      physical_SetRtsCts(arg->cx->physical, 0);
146020812Sjkh    else
146126516Sbrian      return -1;
146226516Sbrian    return 0;
146320812Sjkh  }
146426516Sbrian  return -1;
146520812Sjkh}
146620812Sjkh
146730715Sbrianstatic struct cmdtab const SetCommands[] = {
146836285Sbrian  {"accmap", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
146936285Sbrian  "accmap value", "set accmap hex-value", (const void *)VAR_ACCMAP},
147028679Sbrian  {"authkey", "key", SetVariable, LOCAL_AUTH,
147136285Sbrian  "authentication key", "set authkey|key key", (const void *)VAR_AUTHKEY},
147228679Sbrian  {"authname", NULL, SetVariable, LOCAL_AUTH,
147336285Sbrian  "authentication name", "set authname name", (const void *)VAR_AUTHNAME},
147436285Sbrian  {"autoload", NULL, SetVariable, LOCAL_AUTH,
147536285Sbrian  "auto link [de]activation", "set autoload maxtime maxload mintime minload",
147636285Sbrian  (const void *)VAR_AUTOLOAD},
147736285Sbrian  {"ccpretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
147836285Sbrian  "FSM retry period", "set ccpretry value", (const void *)VAR_CCPRETRY},
147936285Sbrian  {"chapretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
148036285Sbrian  "CHAP retry period", "set chapretry value", (const void *)VAR_CHAPRETRY},
148136285Sbrian  {"ctsrts", "crtscts", SetCtsRts, LOCAL_AUTH | LOCAL_CX,
148236285Sbrian  "Use hardware flow control", "set ctsrts [on|off]"},
148336285Sbrian  {"deflate", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
148436285Sbrian  "deflate window sizes", "set deflate out-winsize in-winsize",
148536285Sbrian  (const void *) VAR_WINSIZE},
148636285Sbrian  {"device", "line", SetVariable, LOCAL_AUTH | LOCAL_CX,
148736285Sbrian  "modem device name", "set device|line device-name[,device-name]",
148836285Sbrian  (const void *) VAR_DEVICE},
148936285Sbrian  {"dial", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
149036285Sbrian  "dialing script", "set dial chat-script", (const void *) VAR_DIAL},
149136285Sbrian  {"dns", NULL, SetVariable, LOCAL_AUTH, "Domain Name Server",
149236285Sbrian  "set dns pri-addr [sec-addr]", (const void *)VAR_DNS},
149336285Sbrian  {"enddisc", NULL, mp_SetEnddisc, LOCAL_AUTH,
149436285Sbrian  "Endpoint Discriminator", "set enddisc [IP|magic|label|psn value]"},
149536285Sbrian  {"escape", NULL, SetEscape, LOCAL_AUTH | LOCAL_CX,
149636285Sbrian  "escape characters", "set escape hex-digit ..."},
149736285Sbrian  {"filter", NULL, filter_Set, LOCAL_AUTH,
149836285Sbrian  "packet filters", "set filter alive|dial|in|out rule-no permit|deny "
149936285Sbrian  "[src_addr[/width]] [dst_addr[/width]] [tcp|udp|icmp [src [lt|eq|gt port]] "
150036285Sbrian  "[dst [lt|eq|gt port]] [estab] [syn] [finrst]]"},
150136285Sbrian  {"hangup", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
150236285Sbrian  "hangup script", "set hangup chat-script", (const void *) VAR_HANGUP},
150336285Sbrian  {"ifaddr", NULL, SetInterfaceAddr, LOCAL_AUTH, "destination address",
150431343Sbrian  "set ifaddr [src-addr [dst-addr [netmask [trg-addr]]]]"},
150536285Sbrian  {"ipcpretry", NULL, SetVariable, LOCAL_AUTH,
150636285Sbrian  "FSM retry period", "set ipcpretry value", (const void *)VAR_IPCPRETRY},
150736285Sbrian  {"lcpretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
150836285Sbrian  "FSM retry period", "set lcpretry value", (const void *)VAR_LCPRETRY},
150936712Sbrian  {"log", NULL, log_SetLevel, LOCAL_AUTH, "log level",
151036712Sbrian  "set log [local] [+|-]async|ccp|chat|command|connect|debug|hdlc|id0|ipcp|"
151136712Sbrian  "lcp|lqm|phase|tcp/ip|timer|tun..."},
151236285Sbrian  {"login", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
151336285Sbrian  "login script", "set login chat-script", (const void *) VAR_LOGIN},
151436285Sbrian  {"lqrperiod", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
151536285Sbrian  "LQR period", "set lqrperiod value", (const void *)VAR_LQRPERIOD},
151636285Sbrian  {"mode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "mode value",
151736285Sbrian  "set mode interactive|auto|ddial|background", (const void *)VAR_MODE},
151836285Sbrian  {"mrru", NULL, SetVariable, LOCAL_AUTH, "MRRU value",
151936285Sbrian  "set mrru value", (const void *)VAR_MRRU},
152036285Sbrian  {"mru", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
152136285Sbrian  "MRU value", "set mru value", (const void *)VAR_MRU},
152236285Sbrian  {"mtu", NULL, SetVariable, LOCAL_AUTH,
152336285Sbrian  "interface MTU value", "set mtu value", (const void *)VAR_MTU},
152436285Sbrian  {"nbns", NULL, SetVariable, LOCAL_AUTH, "NetBIOS Name Server",
152536285Sbrian  "set nbns pri-addr [sec-addr]", (const void *)VAR_NBNS},
152636285Sbrian  {"openmode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "open mode",
152736285Sbrian  "set openmode active|passive [secs]", (const void *)VAR_OPENMODE},
152836285Sbrian  {"papretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
152936285Sbrian  "PAP retry period", "set papretry value", (const void *)VAR_PAPRETRY},
153036285Sbrian  {"parity", NULL, SetModemParity, LOCAL_AUTH | LOCAL_CX,
153136285Sbrian  "modem parity", "set parity [odd|even|none]"},
153236285Sbrian  {"phone", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "telephone number(s)",
153336285Sbrian  "set phone phone1[:phone2[...]]", (const void *)VAR_PHONE},
153436285Sbrian  {"reconnect", NULL, datalink_SetReconnect, LOCAL_AUTH | LOCAL_CX,
153536285Sbrian  "Reconnect timeout", "set reconnect value ntries"},
153636285Sbrian  {"redial", NULL, datalink_SetRedial, LOCAL_AUTH | LOCAL_CX,
153736285Sbrian  "Redial timeout", "set redial value|random[.value|random] [attempts]"},
153828679Sbrian  {"server", "socket", SetServer, LOCAL_AUTH,
153936774Sbrian  "server port", "set server|socket TcpPort|LocalName|none password [mask]"},
154036285Sbrian  {"speed", NULL, SetModemSpeed, LOCAL_AUTH | LOCAL_CX,
154136285Sbrian  "modem speed", "set speed value"},
154236285Sbrian  {"stopped", NULL, SetStoppedTimeout, LOCAL_AUTH | LOCAL_CX,
154336285Sbrian  "STOPPED timeouts", "set stopped [LCPseconds [CCPseconds]]"},
154436285Sbrian  {"timeout", NULL, SetVariable, LOCAL_AUTH, "Idle timeout",
154536285Sbrian  "set timeout idletime", (const void *)VAR_IDLETIMEOUT},
154636285Sbrian  {"vj", NULL, ipcp_vjset, LOCAL_AUTH,
154736285Sbrian  "vj values", "set vj slots|slotcomp [value]"},
154836285Sbrian  {"weight", NULL, mp_SetDatalinkWeight, LOCAL_AUTH | LOCAL_CX,
154936285Sbrian  "datalink weighting", "set weight n"},
155028679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
155131343Sbrian  "Display this message", "set help|? [command]", SetCommands},
155228679Sbrian  {NULL, NULL, NULL},
15536059Samurai};
15546059Samurai
15556059Samuraistatic int
155631343SbrianSetCommand(struct cmdargs const *arg)
15576059Samurai{
155836285Sbrian  if (arg->argc > arg->argn)
155936285Sbrian    FindExec(arg->bundle, SetCommands, arg->argc, arg->argn, arg->argv,
156036285Sbrian             arg->prompt, arg->cx);
156136285Sbrian  else if (arg->prompt)
156236285Sbrian    prompt_Printf(arg->prompt, "Use `set ?' to get a list or `set ? <var>' for"
156326516Sbrian	    " syntax help.\n");
15646059Samurai  else
156536285Sbrian    log_Printf(LogWARN, "set command must have arguments\n");
156626516Sbrian
156726516Sbrian  return 0;
15686059Samurai}
15696059Samurai
15706059Samurai
15716059Samuraistatic int
157231343SbrianAddCommand(struct cmdargs const *arg)
15736059Samurai{
15746059Samurai  struct in_addr dest, gateway, netmask;
157536285Sbrian  int gw, addrs;
15766059Samurai
157736285Sbrian  if (arg->argc != arg->argn+3 && arg->argc != arg->argn+2)
157831598Sbrian    return -1;
157931598Sbrian
158036285Sbrian  addrs = 0;
158136285Sbrian  if (arg->argc == arg->argn+2) {
158236285Sbrian    if (!strcasecmp(arg->argv[arg->argn], "default"))
158336285Sbrian      dest.s_addr = netmask.s_addr = INADDR_ANY;
158431598Sbrian    else {
158536285Sbrian      int width;
158636285Sbrian
158736285Sbrian      if (!ParseAddr(&arg->bundle->ncp.ipcp, 1, arg->argv + arg->argn,
158836285Sbrian	             &dest, &netmask, &width))
158936285Sbrian        return -1;
159036285Sbrian      if (!strncasecmp(arg->argv[arg->argn], "MYADDR", 6))
159136285Sbrian        addrs = ROUTE_DSTMYADDR;
159236285Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "HISADDR", 7))
159336285Sbrian        addrs = ROUTE_DSTHISADDR;
159431598Sbrian    }
159536285Sbrian    gw = 1;
159634536Sbrian  } else {
159736285Sbrian    if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
159836285Sbrian      addrs = ROUTE_DSTMYADDR;
159936285Sbrian      dest = arg->bundle->ncp.ipcp.my_ip;
160036285Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
160136285Sbrian      addrs = ROUTE_DSTHISADDR;
160236285Sbrian      dest = arg->bundle->ncp.ipcp.peer_ip;
160336285Sbrian    } else
160436285Sbrian      dest = GetIpAddr(arg->argv[arg->argn]);
160536285Sbrian    netmask = GetIpAddr(arg->argv[arg->argn+1]);
160631598Sbrian    gw = 2;
16076059Samurai  }
160836285Sbrian
160936285Sbrian  if (strcasecmp(arg->argv[arg->argn+gw], "HISADDR") == 0) {
161036285Sbrian    gateway = arg->bundle->ncp.ipcp.peer_ip;
161136285Sbrian    addrs |= ROUTE_GWHISADDR;
161236285Sbrian  } else if (strcasecmp(arg->argv[arg->argn+gw], "INTERFACE") == 0)
161331598Sbrian    gateway.s_addr = INADDR_ANY;
161431598Sbrian  else
161536285Sbrian    gateway = GetIpAddr(arg->argv[arg->argn+gw]);
161636285Sbrian
161736285Sbrian  if (bundle_SetRoute(arg->bundle, RTM_ADD, dest, gateway, netmask,
161836285Sbrian                  arg->cmd->args ? 1 : 0))
161936285Sbrian    route_Add(&arg->bundle->ncp.ipcp.route, addrs, dest, netmask, gateway);
162036285Sbrian
162131598Sbrian  return 0;
16226059Samurai}
16236059Samurai
16246059Samuraistatic int
162531343SbrianDeleteCommand(struct cmdargs const *arg)
16266059Samurai{
162731598Sbrian  struct in_addr dest, none;
162836285Sbrian  int addrs;
16296059Samurai
163036285Sbrian  if (arg->argc == arg->argn+1) {
163136285Sbrian    if(strcasecmp(arg->argv[arg->argn], "all") == 0) {
163236285Sbrian      route_IfDelete(arg->bundle, 0);
163336285Sbrian      route_DeleteAll(&arg->bundle->ncp.ipcp.route);
163436285Sbrian    } else {
163536285Sbrian      addrs = 0;
163636285Sbrian      if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
163736285Sbrian        dest = arg->bundle->ncp.ipcp.my_ip;
163836285Sbrian        addrs = ROUTE_DSTMYADDR;
163936285Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
164036285Sbrian        dest = arg->bundle->ncp.ipcp.peer_ip;
164136285Sbrian        addrs = ROUTE_DSTHISADDR;
164236285Sbrian      } else {
164336285Sbrian        if (strcasecmp(arg->argv[arg->argn], "default") == 0)
164436285Sbrian          dest.s_addr = INADDR_ANY;
164536285Sbrian        else
164636285Sbrian          dest = GetIpAddr(arg->argv[arg->argn]);
164736285Sbrian        addrs = ROUTE_STATIC;
164836285Sbrian      }
164931598Sbrian      none.s_addr = INADDR_ANY;
165036285Sbrian      bundle_SetRoute(arg->bundle, RTM_DELETE, dest, none, none,
165136285Sbrian                      arg->cmd->args ? 1 : 0);
165236285Sbrian      route_Delete(&arg->bundle->ncp.ipcp.route, addrs, dest);
165331598Sbrian    }
165434536Sbrian  } else
165526516Sbrian    return -1;
165626516Sbrian
165726516Sbrian  return 0;
16586059Samurai}
16596059Samurai
166031343Sbrian#ifndef NOALIAS
166126031Sbrianstatic struct cmdtab const AliasCommands[] =
166226031Sbrian{
166336285Sbrian  {"addr", NULL, alias_RedirectAddr, LOCAL_AUTH,
166436285Sbrian   "static address translation", "alias addr [addr_local addr_alias]"},
166536285Sbrian  {"deny_incoming", NULL, AliasOption, LOCAL_AUTH,
166636285Sbrian   "stop incoming connections", "alias deny_incoming [yes|no]",
166736285Sbrian   (const void *) PKT_ALIAS_DENY_INCOMING},
166828679Sbrian  {"enable", NULL, AliasEnable, LOCAL_AUTH,
166936285Sbrian   "enable IP aliasing", "alias enable [yes|no]"},
167028679Sbrian  {"log", NULL, AliasOption, LOCAL_AUTH,
167136285Sbrian   "log aliasing link creation", "alias log [yes|no]",
167236285Sbrian   (const void *) PKT_ALIAS_LOG},
167336285Sbrian  {"port", NULL, alias_RedirectPort, LOCAL_AUTH,
167436285Sbrian   "port redirection", "alias port [proto addr_local:port_local  port_alias]"},
167528679Sbrian  {"same_ports", NULL, AliasOption, LOCAL_AUTH,
167636285Sbrian   "try to leave port numbers unchanged", "alias same_ports [yes|no]",
167736285Sbrian   (const void *) PKT_ALIAS_SAME_PORTS},
167836285Sbrian  {"unregistered_only", NULL, AliasOption, LOCAL_AUTH,
167936285Sbrian   "alias unregistered (private) IP address space only",
168036285Sbrian   "alias unregistered_only [yes|no]",
168136285Sbrian   (const void *) PKT_ALIAS_UNREGISTERED_ONLY},
168228679Sbrian  {"use_sockets", NULL, AliasOption, LOCAL_AUTH,
168336285Sbrian   "allocate host sockets", "alias use_sockets [yes|no]",
168436285Sbrian   (const void *) PKT_ALIAS_USE_SOCKETS},
168528679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
168636285Sbrian   "Display this message", "alias help|? [command]", AliasCommands},
168728679Sbrian  {NULL, NULL, NULL},
168826031Sbrian};
168926031Sbrian
169026031Sbrian
169126031Sbrianstatic int
169231343SbrianAliasCommand(struct cmdargs const *arg)
169326031Sbrian{
169436285Sbrian  if (arg->argc > arg->argn)
169536285Sbrian    FindExec(arg->bundle, AliasCommands, arg->argc, arg->argn, arg->argv,
169636285Sbrian             arg->prompt, arg->cx);
169736285Sbrian  else if (arg->prompt)
169836285Sbrian    prompt_Printf(arg->prompt, "Use `alias help' to get a list or `alias help"
169936285Sbrian            " <option>' for syntax help.\n");
170026031Sbrian  else
170136285Sbrian    log_Printf(LogWARN, "alias command must have arguments\n");
170226516Sbrian
170326516Sbrian  return 0;
170426031Sbrian}
170526031Sbrian
170626031Sbrianstatic int
170731343SbrianAliasEnable(struct cmdargs const *arg)
170826031Sbrian{
170936285Sbrian  if (arg->argc == arg->argn+1) {
171036285Sbrian    if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
171137191Sbrian      arg->bundle->AliasEnabled = 1;
171237191Sbrian      return 0;
171336285Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "no") == 0) {
171437191Sbrian      arg->bundle->AliasEnabled = 0;
171526516Sbrian      return 0;
171626142Sbrian    }
171735449Sbrian  }
171836285Sbrian
171926516Sbrian  return -1;
172026031Sbrian}
172126031Sbrian
172226031Sbrian
172326031Sbrianstatic int
172431343SbrianAliasOption(struct cmdargs const *arg)
172526031Sbrian{
172636285Sbrian  unsigned param = (unsigned)arg->cmd->args;
172736285Sbrian  if (arg->argc == arg->argn+1) {
172836285Sbrian    if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
172937191Sbrian      if (arg->bundle->AliasEnabled) {
173037191Sbrian	PacketAliasSetMode(param, param);
173128679Sbrian	return 0;
173228679Sbrian      }
173336285Sbrian      log_Printf(LogWARN, "alias not enabled\n");
173436285Sbrian    } else if (strcmp(arg->argv[arg->argn], "no") == 0) {
173537191Sbrian      if (arg->bundle->AliasEnabled) {
173637191Sbrian	PacketAliasSetMode(0, param);
173728679Sbrian	return 0;
173828679Sbrian      }
173936285Sbrian      log_Printf(LogWARN, "alias not enabled\n");
174028679Sbrian    }
174135449Sbrian  }
174228679Sbrian  return -1;
174326031Sbrian}
174431343Sbrian#endif /* #ifndef NOALIAS */
174531121Sbrian
174631121Sbrianstatic struct cmdtab const AllowCommands[] = {
174736285Sbrian  {"modes", "mode", AllowModes, LOCAL_AUTH,
174836285Sbrian  "Only allow certain ppp modes", "allow modes mode..."},
174931121Sbrian  {"users", "user", AllowUsers, LOCAL_AUTH,
175031121Sbrian  "Allow users access to ppp", "allow users logname..."},
175131121Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
175231343Sbrian  "Display this message", "allow help|? [command]", AllowCommands},
175331121Sbrian  {NULL, NULL, NULL},
175431121Sbrian};
175531121Sbrian
175631121Sbrianstatic int
175731343SbrianAllowCommand(struct cmdargs const *arg)
175831121Sbrian{
175936285Sbrian  /* arg->bundle may be NULL (see system_IsValid()) ! */
176036285Sbrian  if (arg->argc > arg->argn)
176136285Sbrian    FindExec(arg->bundle, AllowCommands, arg->argc, arg->argn, arg->argv,
176236285Sbrian             arg->prompt, arg->cx);
176336285Sbrian  else if (arg->prompt)
176436285Sbrian    prompt_Printf(arg->prompt, "Use `allow ?' to get a list or `allow ? <cmd>'"
176536285Sbrian                  " for syntax help.\n");
176631121Sbrian  else
176736285Sbrian    log_Printf(LogWARN, "allow command must have arguments\n");
176831121Sbrian
176931121Sbrian  return 0;
177031121Sbrian}
177136285Sbrian
177236285Sbrianstatic int
177336285SbrianLinkCommand(struct cmdargs const *arg)
177436285Sbrian{
177536285Sbrian  if (arg->argc > arg->argn+1) {
177636285Sbrian    char namelist[LINE_LEN];
177736285Sbrian    struct datalink *cx;
177836285Sbrian    char *name;
177936285Sbrian    int result = 0;
178036285Sbrian
178136285Sbrian    if (!strcmp(arg->argv[arg->argn], "*")) {
178236285Sbrian      struct datalink *dl;
178336285Sbrian
178436285Sbrian      cx = arg->bundle->links;
178536285Sbrian      while (cx) {
178636285Sbrian        /* Watch it, the command could be a ``remove'' */
178736285Sbrian        dl = cx->next;
178836285Sbrian        FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
178936285Sbrian                 arg->prompt, cx);
179036285Sbrian        for (cx = arg->bundle->links; cx; cx = cx->next)
179136285Sbrian          if (cx == dl)
179236285Sbrian            break;		/* Pointer's still valid ! */
179336285Sbrian      }
179436285Sbrian    } else {
179536285Sbrian      strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
179636285Sbrian      namelist[sizeof namelist - 1] = '\0';
179736285Sbrian      for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
179836285Sbrian        if (!bundle2datalink(arg->bundle, name)) {
179936285Sbrian          log_Printf(LogWARN, "link: %s: Invalid link name\n", name);
180036285Sbrian          return 1;
180136285Sbrian        }
180236285Sbrian
180336285Sbrian      strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
180436285Sbrian      namelist[sizeof namelist - 1] = '\0';
180536285Sbrian      for(name = strtok(namelist, ", "); name; name = strtok(NULL,", ")) {
180636285Sbrian        cx = bundle2datalink(arg->bundle, name);
180736285Sbrian        if (cx)
180836285Sbrian          FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
180936285Sbrian                   arg->prompt, cx);
181036285Sbrian        else {
181136285Sbrian          log_Printf(LogWARN, "link: %s: Invalidated link name !\n", name);
181236285Sbrian          result++;
181336285Sbrian        }
181436285Sbrian      }
181536285Sbrian    }
181636285Sbrian    return result;
181736285Sbrian  }
181836285Sbrian
181936285Sbrian  log_Printf(LogWARN, "Usage: %s\n", arg->cmd->syntax);
182036285Sbrian  return 2;
182136285Sbrian}
182236285Sbrian
182336285Sbrianstruct link *
182436285Sbriancommand_ChooseLink(struct cmdargs const *arg)
182536285Sbrian{
182636285Sbrian  if (arg->cx)
182736285Sbrian    return &arg->cx->physical->link;
182837210Sbrian  else if (!arg->bundle->ncp.mp.cfg.mrru) {
182936285Sbrian    struct datalink *dl = bundle2datalink(arg->bundle, NULL);
183037210Sbrian    if (dl)
183137210Sbrian      return &dl->physical->link;
183236285Sbrian  }
183337210Sbrian  return &arg->bundle->ncp.mp.link;
183436285Sbrian}
183536285Sbrian
183636285Sbrianstatic const char *
183736285Sbrianident_cmd(const char *cmd, unsigned *keep, unsigned *add)
183836285Sbrian{
183936285Sbrian  const char *result;
184036285Sbrian
184136285Sbrian  switch (*cmd) {
184236285Sbrian    case 'A':
184336285Sbrian    case 'a':
184436285Sbrian      result = "accept";
184536285Sbrian      *keep = NEG_MYMASK;
184636285Sbrian      *add = NEG_ACCEPTED;
184736285Sbrian      break;
184836285Sbrian    case 'D':
184936285Sbrian    case 'd':
185036285Sbrian      switch (cmd[1]) {
185136285Sbrian        case 'E':
185236285Sbrian        case 'e':
185336285Sbrian          result = "deny";
185436285Sbrian          *keep = NEG_MYMASK;
185536285Sbrian          *add = 0;
185636285Sbrian          break;
185736285Sbrian        case 'I':
185836285Sbrian        case 'i':
185936285Sbrian          result = "disable";
186036285Sbrian          *keep = NEG_HISMASK;
186136285Sbrian          *add = 0;
186236285Sbrian          break;
186336285Sbrian        default:
186436285Sbrian          return NULL;
186536285Sbrian      }
186636285Sbrian      break;
186736285Sbrian    case 'E':
186836285Sbrian    case 'e':
186936285Sbrian      result = "enable";
187036285Sbrian      *keep = NEG_HISMASK;
187136285Sbrian      *add = NEG_ENABLED;
187236285Sbrian      break;
187336285Sbrian    default:
187436285Sbrian      return NULL;
187536285Sbrian  }
187636285Sbrian
187736285Sbrian  return result;
187836285Sbrian}
187936285Sbrian
188036285Sbrianstatic int
188136285SbrianOptSet(struct cmdargs const *arg)
188236285Sbrian{
188337210Sbrian  int bit = (long)arg->cmd->args ? 1 : 0;
188436285Sbrian  const char *cmd;
188536285Sbrian  unsigned keep;			/* Keep these bits */
188636285Sbrian  unsigned add;				/* Add these bits */
188736285Sbrian
188836285Sbrian  if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL)
188936285Sbrian    return 1;
189036285Sbrian
189136285Sbrian  if (add)
189236285Sbrian    arg->bundle->cfg.opt |= bit;
189336285Sbrian  else
189436285Sbrian    arg->bundle->cfg.opt &= ~bit;
189536285Sbrian  return 0;
189636285Sbrian}
189736285Sbrian
189836285Sbrianstatic int
189936285SbrianNegotiateSet(struct cmdargs const *arg)
190036285Sbrian{
190137210Sbrian  long param = (long)arg->cmd->args;
190236285Sbrian  struct link *l = command_ChooseLink(arg);	/* LOCAL_CX_OPT uses this */
190336285Sbrian  struct datalink *cx = arg->cx;	/* LOCAL_CX uses this */
190436285Sbrian  const char *cmd;
190536285Sbrian  unsigned keep;			/* Keep these bits */
190636285Sbrian  unsigned add;				/* Add these bits */
190736285Sbrian
190836285Sbrian  if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL)
190936285Sbrian    return 1;
191036285Sbrian
191136285Sbrian  if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
191236285Sbrian    log_Printf(LogWARN, "%s %s: No context (use the `link' command)\n",
191336285Sbrian              cmd, arg->cmd->name);
191436285Sbrian    return 2;
191536285Sbrian  } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
191636285Sbrian    log_Printf(LogWARN, "%s %s: Redundant context (%s) ignored\n",
191736285Sbrian              cmd, arg->cmd->name, cx->name);
191836285Sbrian    cx = NULL;
191936285Sbrian  }
192036285Sbrian
192136285Sbrian  switch (param) {
192236285Sbrian    case NEG_ACFCOMP:
192336285Sbrian      cx->physical->link.lcp.cfg.acfcomp &= keep;
192436285Sbrian      cx->physical->link.lcp.cfg.acfcomp |= add;
192536285Sbrian      break;
192636285Sbrian    case NEG_CHAP:
192736285Sbrian      cx->physical->link.lcp.cfg.chap &= keep;
192836285Sbrian      cx->physical->link.lcp.cfg.chap |= add;
192936285Sbrian      break;
193036285Sbrian    case NEG_DEFLATE:
193136285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE] &= keep;
193236285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE] |= add;
193336285Sbrian      break;
193436285Sbrian    case NEG_DNS:
193536285Sbrian      arg->bundle->ncp.ipcp.cfg.ns.dns_neg &= keep;
193636285Sbrian      arg->bundle->ncp.ipcp.cfg.ns.dns_neg |= add;
193736285Sbrian      break;
193836285Sbrian    case NEG_LQR:
193936285Sbrian      cx->physical->link.lcp.cfg.lqr &= keep;
194036285Sbrian      cx->physical->link.lcp.cfg.lqr |= add;
194136285Sbrian      break;
194236285Sbrian    case NEG_PAP:
194336285Sbrian      cx->physical->link.lcp.cfg.pap &= keep;
194436285Sbrian      cx->physical->link.lcp.cfg.pap |= add;
194536285Sbrian      break;
194636285Sbrian    case NEG_PPPDDEFLATE:
194736285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE24] &= keep;
194836285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE24] |= add;
194936285Sbrian      break;
195036285Sbrian    case NEG_PRED1:
195136285Sbrian      l->ccp.cfg.neg[CCP_NEG_PRED1] &= keep;
195236285Sbrian      l->ccp.cfg.neg[CCP_NEG_PRED1] |= add;
195336285Sbrian      break;
195436285Sbrian    case NEG_PROTOCOMP:
195536285Sbrian      cx->physical->link.lcp.cfg.protocomp &= keep;
195636285Sbrian      cx->physical->link.lcp.cfg.protocomp |= add;
195736285Sbrian      break;
195836285Sbrian    case NEG_SHORTSEQ:
195936285Sbrian      if (bundle_Phase(arg->bundle) != PHASE_DEAD)
196036285Sbrian        log_Printf(LogWARN, "shortseq: Only changable at phase DEAD\n");
196136285Sbrian      else {
196236285Sbrian        arg->bundle->ncp.mp.cfg.shortseq &= keep;
196336285Sbrian        arg->bundle->ncp.mp.cfg.shortseq |= add;
196436285Sbrian      }
196536285Sbrian      break;
196636285Sbrian    case NEG_VJCOMP:
196736285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.neg &= keep;
196836285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.neg |= add;
196936285Sbrian      break;
197036285Sbrian  }
197136285Sbrian
197236285Sbrian  return 0;
197336285Sbrian}
197436285Sbrian
197536285Sbrianstatic struct cmdtab const NegotiateCommands[] = {
197636285Sbrian  {"idcheck", NULL, OptSet, LOCAL_AUTH, "Check FSM reply ids",
197736285Sbrian  "disable|enable", (const void *)OPT_IDCHECK},
197836285Sbrian  {"loopback", NULL, OptSet, LOCAL_AUTH, "Loop packets for local iface",
197936285Sbrian  "disable|enable", (const void *)OPT_LOOPBACK},
198036285Sbrian  {"passwdauth", NULL, OptSet, LOCAL_AUTH, "Use passwd file",
198136285Sbrian  "disable|enable", (const void *)OPT_PASSWDAUTH},
198236285Sbrian  {"proxy", NULL, OptSet, LOCAL_AUTH, "Create proxy ARP entry",
198336285Sbrian  "disable|enable", (const void *)OPT_PROXY},
198436285Sbrian  {"sroutes", NULL, OptSet, LOCAL_AUTH, "Use sticky routes",
198536285Sbrian  "disable|enable", (const void *)OPT_SROUTES},
198636285Sbrian  {"throughput", NULL, OptSet, LOCAL_AUTH, "Rolling throughput",
198736285Sbrian  "disable|enable", (const void *)OPT_THROUGHPUT},
198836285Sbrian  {"utmp", NULL, OptSet, LOCAL_AUTH, "Log connections in utmp",
198936285Sbrian  "disable|enable", (const void *)OPT_UTMP},
199036285Sbrian
199136285Sbrian#define OPT_MAX 7	/* accept/deny allowed below and not above */
199236285Sbrian
199336285Sbrian  {"acfcomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
199436285Sbrian  "Address & Control field compression", "accept|deny|disable|enable",
199536285Sbrian  (const void *)NEG_ACFCOMP},
199636285Sbrian  {"chap", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
199736285Sbrian  "Challenge Handshake Authentication Protocol", "accept|deny|disable|enable",
199836285Sbrian  (const void *)NEG_CHAP},
199936285Sbrian  {"deflate", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
200036285Sbrian  "Deflate compression", "accept|deny|disable|enable",
200136285Sbrian  (const void *)NEG_DEFLATE},
200236285Sbrian  {"deflate24", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
200336285Sbrian  "Deflate (type 24) compression", "accept|deny|disable|enable",
200436285Sbrian  (const void *)NEG_PPPDDEFLATE},
200536285Sbrian  {"dns", NULL, NegotiateSet, LOCAL_AUTH,
200636285Sbrian  "DNS specification", "accept|deny|disable|enable", (const void *)NEG_DNS},
200736285Sbrian  {"lqr", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
200836285Sbrian  "Link Quality Reports", "accept|deny|disable|enable",
200936285Sbrian  (const void *)NEG_LQR},
201036285Sbrian  {"pap", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
201136285Sbrian  "Password Authentication protocol", "accept|deny|disable|enable",
201236285Sbrian  (const void *)NEG_PAP},
201336285Sbrian  {"pred1", "predictor1", NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
201436285Sbrian  "Predictor 1 compression", "accept|deny|disable|enable",
201536285Sbrian  (const void *)NEG_PRED1},
201636285Sbrian  {"protocomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
201736285Sbrian  "Protocol field compression", "accept|deny|disable|enable",
201836285Sbrian  (const void *)NEG_PROTOCOMP},
201936285Sbrian  {"shortseq", NULL, NegotiateSet, LOCAL_AUTH,
202036285Sbrian  "MP Short Sequence Numbers", "accept|deny|disable|enable",
202136285Sbrian  (const void *)NEG_SHORTSEQ},
202236285Sbrian  {"vjcomp", NULL, NegotiateSet, LOCAL_AUTH,
202336285Sbrian  "Van Jacobson header compression", "accept|deny|disable|enable",
202436285Sbrian  (const void *)NEG_VJCOMP},
202536285Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
202636285Sbrian  "Display this message", "accept|deny|disable|enable help|? [value]",
202736285Sbrian  NegotiateCommands},
202836285Sbrian  {NULL, NULL, NULL},
202936285Sbrian};
203036285Sbrian
203136285Sbrianstatic int
203236285SbrianNegotiateCommand(struct cmdargs const *arg)
203336285Sbrian{
203436285Sbrian  if (arg->argc > arg->argn) {
203536285Sbrian    char const *argv[3];
203636285Sbrian    unsigned keep, add;
203736285Sbrian    int n;
203836285Sbrian
203936285Sbrian    if ((argv[0] = ident_cmd(arg->argv[arg->argn-1], &keep, &add)) == NULL)
204036285Sbrian      return -1;
204136285Sbrian    argv[2] = NULL;
204236285Sbrian
204336285Sbrian    for (n = arg->argn; n < arg->argc; n++) {
204436285Sbrian      argv[1] = arg->argv[n];
204536285Sbrian      FindExec(arg->bundle, NegotiateCommands + (keep == NEG_HISMASK ?
204636285Sbrian               0 : OPT_MAX), 2, 1, argv, arg->prompt, arg->cx);
204736285Sbrian    }
204836285Sbrian  } else if (arg->prompt)
204936285Sbrian    prompt_Printf(arg->prompt, "Use `%s ?' to get a list.\n",
205036285Sbrian	    arg->argv[arg->argn-1]);
205136285Sbrian  else
205236285Sbrian    log_Printf(LogWARN, "%s command must have arguments\n",
205336285Sbrian              arg->argv[arg->argn] );
205436285Sbrian
205536285Sbrian  return 0;
205636285Sbrian}
205736285Sbrian
205836285Sbrianconst char *
205936285Sbriancommand_ShowNegval(unsigned val)
206036285Sbrian{
206136285Sbrian  switch (val&3) {
206236285Sbrian    case 1: return "disabled & accepted";
206336285Sbrian    case 2: return "enabled & denied";
206436285Sbrian    case 3: return "enabled & accepted";
206536285Sbrian  }
206636285Sbrian  return "disabled & denied";
206736285Sbrian}
206836934Sbrian
206936934Sbrianstatic int
207036934SbrianClearCommand(struct cmdargs const *arg)
207136934Sbrian{
207236934Sbrian  struct pppThroughput *t;
207336934Sbrian  struct datalink *cx;
207436934Sbrian  int i, clear_type;
207536934Sbrian
207636934Sbrian  if (arg->argc < arg->argn + 1)
207736934Sbrian    return -1;
207836934Sbrian
207936934Sbrian  if (strcasecmp(arg->argv[arg->argn], "modem") == 0) {
208036934Sbrian    cx = arg->cx;
208136934Sbrian    if (!cx)
208236934Sbrian      cx = bundle2datalink(arg->bundle, NULL);
208336934Sbrian    if (!cx) {
208436934Sbrian      log_Printf(LogWARN, "A link must be specified for ``clear modem''\n");
208536934Sbrian      return 1;
208636934Sbrian    }
208736934Sbrian    t = &cx->physical->link.throughput;
208836934Sbrian  } else if (strcasecmp(arg->argv[arg->argn], "ipcp") == 0)
208936934Sbrian    t = &arg->bundle->ncp.ipcp.throughput;
209036934Sbrian  else
209136934Sbrian    return -1;
209236934Sbrian
209336934Sbrian  if (arg->argc > arg->argn + 1) {
209436934Sbrian    clear_type = 0;
209536934Sbrian    for (i = arg->argn + 1; i < arg->argc; i++)
209636934Sbrian      if (strcasecmp(arg->argv[i], "overall") == 0)
209736934Sbrian        clear_type |= THROUGHPUT_OVERALL;
209836934Sbrian      else if (strcasecmp(arg->argv[i], "current") == 0)
209936934Sbrian        clear_type |= THROUGHPUT_CURRENT;
210036934Sbrian      else if (strcasecmp(arg->argv[i], "peak") == 0)
210136934Sbrian        clear_type |= THROUGHPUT_PEAK;
210236934Sbrian      else
210336934Sbrian        return -1;
210436934Sbrian  } else
210536934Sbrian    clear_type = THROUGHPUT_ALL;
210636934Sbrian
210736934Sbrian  throughput_clear(t, clear_type, arg->prompt);
210836934Sbrian  return 0;
210936934Sbrian}
2110