command.c revision 36465
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 *
2036465Sbrian * $Id: command.c,v 1.135 1998/05/21 21:44:44 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>
3936285Sbrian#include <signal.h>
4030715Sbrian#include <stdio.h>
4130715Sbrian#include <stdlib.h>
4230715Sbrian#include <string.h>
4330715Sbrian#include <sys/wait.h>
4430715Sbrian#include <termios.h>
4530715Sbrian#include <unistd.h>
4630715Sbrian
4731343Sbrian#include "command.h"
4830715Sbrian#include "mbuf.h"
4930715Sbrian#include "log.h"
5030715Sbrian#include "defs.h"
5130715Sbrian#include "timer.h"
526059Samurai#include "fsm.h"
536059Samurai#include "lcp.h"
5431690Sbrian#include "iplist.h"
5536285Sbrian#include "throughput.h"
5636285Sbrian#include "slcompress.h"
576059Samurai#include "ipcp.h"
586059Samurai#include "modem.h"
5931343Sbrian#ifndef NOALIAS
6026031Sbrian#include "alias_cmd.h"
6131343Sbrian#endif
6236285Sbrian#include "lqr.h"
636059Samurai#include "hdlc.h"
6426142Sbrian#include "loadalias.h"
6525630Sbrian#include "systems.h"
6636285Sbrian#include "filter.h"
6736285Sbrian#include "descriptor.h"
6830715Sbrian#include "main.h"
6930715Sbrian#include "route.h"
7030715Sbrian#include "ccp.h"
7131080Sbrian#include "auth.h"
7236285Sbrian#include "async.h"
7336285Sbrian#include "link.h"
7436285Sbrian#include "physical.h"
7536285Sbrian#include "mp.h"
7636285Sbrian#include "bundle.h"
7736285Sbrian#include "server.h"
7836285Sbrian#include "prompt.h"
7936285Sbrian#include "chat.h"
8036285Sbrian#include "chap.h"
8136285Sbrian#include "datalink.h"
826059Samurai
8336285Sbrian/* ``set'' values */
8436285Sbrian#define	VAR_AUTHKEY	0
8536285Sbrian#define	VAR_DIAL	1
8636285Sbrian#define	VAR_LOGIN	2
8736285Sbrian#define	VAR_AUTHNAME	3
8836285Sbrian#define	VAR_AUTOLOAD	4
8936285Sbrian#define	VAR_WINSIZE	5
9036285Sbrian#define	VAR_DEVICE	6
9136285Sbrian#define	VAR_ACCMAP	7
9236285Sbrian#define	VAR_MRRU	8
9336285Sbrian#define	VAR_MRU		9
9436285Sbrian#define	VAR_MTU		10
9536285Sbrian#define	VAR_OPENMODE	11
9636285Sbrian#define	VAR_PHONE	12
9736285Sbrian#define	VAR_HANGUP	13
9836285Sbrian#define	VAR_IDLETIMEOUT	14
9936285Sbrian#define	VAR_LQRPERIOD	15
10036285Sbrian#define	VAR_LCPRETRY	16
10136285Sbrian#define	VAR_CHAPRETRY	17
10236285Sbrian#define	VAR_PAPRETRY	18
10336285Sbrian#define	VAR_CCPRETRY	19
10436285Sbrian#define	VAR_IPCPRETRY	20
10536285Sbrian#define	VAR_DNS		21
10636285Sbrian#define	VAR_NBNS	22
10736285Sbrian#define	VAR_MODE	23
1086059Samurai
10936285Sbrian/* ``accept|deny|disable|enable'' masks */
11036285Sbrian#define NEG_HISMASK (1)
11136285Sbrian#define NEG_MYMASK (2)
11236285Sbrian
11336285Sbrian/* ``accept|deny|disable|enable'' values */
11436285Sbrian#define NEG_ACFCOMP	40
11536285Sbrian#define NEG_CHAP	41
11636285Sbrian#define NEG_DEFLATE	42
11736285Sbrian#define NEG_LQR		43
11836285Sbrian#define NEG_PAP		44
11936285Sbrian#define NEG_PPPDDEFLATE	45
12036285Sbrian#define NEG_PRED1	46
12136285Sbrian#define NEG_PROTOCOMP	47
12236285Sbrian#define NEG_SHORTSEQ	48
12336285Sbrian#define NEG_VJCOMP	49
12436285Sbrian#define NEG_DNS		50
12536285Sbrian
12636285Sbrianconst char Version[] = "2.0-beta";
12736465Sbrianconst char VersionDate[] = "$Date: 1998/05/21 21:44:44 $";
12836285Sbrian
12936285Sbrianstatic int ShowCommand(struct cmdargs const *);
13036285Sbrianstatic int TerminalCommand(struct cmdargs const *);
13136285Sbrianstatic int QuitCommand(struct cmdargs const *);
13236285Sbrianstatic int OpenCommand(struct cmdargs const *);
13336285Sbrianstatic int CloseCommand(struct cmdargs const *);
13436285Sbrianstatic int DownCommand(struct cmdargs const *);
13536285Sbrianstatic int AllowCommand(struct cmdargs const *);
13636285Sbrianstatic int SetCommand(struct cmdargs const *);
13736285Sbrianstatic int LinkCommand(struct cmdargs const *);
13836285Sbrianstatic int AddCommand(struct cmdargs const *);
13936285Sbrianstatic int DeleteCommand(struct cmdargs const *);
14036285Sbrianstatic int NegotiateCommand(struct cmdargs const *);
14131343Sbrian#ifndef NOALIAS
14236285Sbrianstatic int AliasCommand(struct cmdargs const *);
14336285Sbrianstatic int AliasEnable(struct cmdargs const *);
14436285Sbrianstatic int AliasOption(struct cmdargs const *);
14531343Sbrian#endif
1466059Samurai
14736285Sbrianstatic const char *
14836285Sbrianshowcx(struct cmdtab const *cmd)
14936285Sbrian{
15036285Sbrian  if (cmd->lauth & LOCAL_CX)
15136285Sbrian    return "(c)";
15236285Sbrian  else if (cmd->lauth & LOCAL_CX_OPT)
15336285Sbrian    return "(o)";
15436285Sbrian
15536285Sbrian  return "";
15636285Sbrian}
15736285Sbrian
1586059Samuraistatic int
15931343SbrianHelpCommand(struct cmdargs const *arg)
1606059Samurai{
16128679Sbrian  struct cmdtab const *cmd;
16236285Sbrian  int n, cmax, dmax, cols, cxlen;
16336285Sbrian  const char *cx;
1646059Samurai
16536285Sbrian  if (!arg->prompt) {
16636285Sbrian    log_Printf(LogWARN, "help: Cannot help without a prompt\n");
16726516Sbrian    return 0;
16836285Sbrian  }
16926516Sbrian
17036285Sbrian  if (arg->argc > arg->argn) {
17136285Sbrian    for (cmd = arg->cmdtab; cmd->name || cmd->alias; cmd++)
17236285Sbrian      if ((cmd->lauth & arg->prompt->auth) &&
17336285Sbrian          ((cmd->name && !strcasecmp(cmd->name, arg->argv[arg->argn])) ||
17436285Sbrian           (cmd->alias && !strcasecmp(cmd->alias, arg->argv[arg->argn])))) {
17536285Sbrian	prompt_Printf(arg->prompt, "%s %s\n", cmd->syntax, showcx(cmd));
17628679Sbrian	return 0;
1776059Samurai      }
17826516Sbrian    return -1;
1796059Samurai  }
18036285Sbrian
18131372Sbrian  cmax = dmax = 0;
18236285Sbrian  for (cmd = arg->cmdtab; cmd->func; cmd++)
18336285Sbrian    if (cmd->name && (cmd->lauth & arg->prompt->auth)) {
18436285Sbrian      if ((n = strlen(cmd->name) + strlen(showcx(cmd))) > cmax)
18531372Sbrian        cmax = n;
18631372Sbrian      if ((n = strlen(cmd->helpmes)) > dmax)
18731372Sbrian        dmax = n;
18831372Sbrian    }
18931372Sbrian
19031372Sbrian  cols = 80 / (dmax + cmax + 3);
1916059Samurai  n = 0;
19236285Sbrian  prompt_Printf(arg->prompt, "(o) = Optional context,"
19336285Sbrian                " (c) = Context required\n");
19436285Sbrian  for (cmd = arg->cmdtab; cmd->func; cmd++)
19536285Sbrian    if (cmd->name && (cmd->lauth & arg->prompt->auth)) {
19636285Sbrian      cx = showcx(cmd);
19736285Sbrian      cxlen = cmax - strlen(cmd->name);
19836285Sbrian      prompt_Printf(arg->prompt, " %s%-*.*s: %-*.*s",
19936285Sbrian              cmd->name, cxlen, cxlen, cx, dmax, dmax, cmd->helpmes);
20031372Sbrian      if (++n % cols == 0)
20136285Sbrian        prompt_Printf(arg->prompt, "\n");
2026059Samurai    }
20331372Sbrian  if (n % cols != 0)
20436285Sbrian    prompt_Printf(arg->prompt, "\n");
20526516Sbrian
20626516Sbrian  return 0;
2076059Samurai}
2086059Samurai
20936285Sbrianstatic int
21036285SbrianCloneCommand(struct cmdargs const *arg)
2116059Samurai{
21236285Sbrian  char namelist[LINE_LEN];
21336285Sbrian  char *name;
21436285Sbrian  int f;
2156059Samurai
21636285Sbrian  if (arg->argc == arg->argn)
21736285Sbrian    return -1;
21836285Sbrian
21936285Sbrian  namelist[sizeof namelist - 1] = '\0';
22036285Sbrian  for (f = arg->argn; f < arg->argc; f++) {
22136285Sbrian    strncpy(namelist, arg->argv[f], sizeof namelist - 1);
22236285Sbrian    for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
22336285Sbrian      bundle_DatalinkClone(arg->bundle, arg->cx, name);
2246059Samurai  }
22536285Sbrian
22636285Sbrian  return 0;
2276059Samurai}
2286059Samurai
2296059Samuraistatic int
23036285SbrianRemoveCommand(struct cmdargs const *arg)
2316059Samurai{
23236285Sbrian  if (arg->argc != arg->argn)
23336285Sbrian    return -1;
23411336Samurai
23536285Sbrian  if (arg->cx->state != DATALINK_CLOSED) {
23636285Sbrian    log_Printf(LogWARN, "remove: Cannot delete links that aren't closed\n");
23736285Sbrian    return 2;
2386059Samurai  }
23926516Sbrian
24036285Sbrian  bundle_DatalinkRemove(arg->bundle, arg->cx);
24136285Sbrian  return 0;
24236285Sbrian}
24332711Sbrian
24436285Sbrianstatic int
24536285SbrianRenameCommand(struct cmdargs const *arg)
24636285Sbrian{
24736285Sbrian  if (arg->argc != arg->argn + 1)
24836285Sbrian    return -1;
24931121Sbrian
25036285Sbrian  if (bundle_RenameDatalink(arg->bundle, arg->cx, arg->argv[arg->argn]))
25136285Sbrian    return 0;
25236285Sbrian
25336285Sbrian  log_Printf(LogWARN, "%s -> %s: target name already exists\n",
25436285Sbrian             arg->cx->name, arg->argv[arg->argn]);
25536285Sbrian  return 1;
25636285Sbrian}
25736285Sbrian
25836285Sbrianint
25936285SbrianLoadCommand(struct cmdargs const *arg)
26036285Sbrian{
26136285Sbrian  const char *name;
26236285Sbrian
26336285Sbrian  if (arg->argc > arg->argn)
26436285Sbrian    name = arg->argv[arg->argn];
26536285Sbrian  else
26636285Sbrian    name = "default";
26736285Sbrian
26836285Sbrian  if (!system_IsValid(name, arg->prompt, arg->bundle->phys_type)) {
26936285Sbrian    log_Printf(LogERROR, "%s: Label not allowed\n", name);
27036285Sbrian    return 1;
27136285Sbrian  } else {
27236285Sbrian    /*
27336285Sbrian     * Set the label before & after so that `set enddisc' works and
27436285Sbrian     * we handle nested `load' commands.
27536285Sbrian     */
27636285Sbrian    bundle_SetLabel(arg->bundle, arg->argc > arg->argn ? name : NULL);
27736285Sbrian    if (system_Select(arg->bundle, name, CONFFILE, arg->prompt) < 0) {
27836285Sbrian      bundle_SetLabel(arg->bundle, NULL);
27936285Sbrian      log_Printf(LogWARN, "%s: label not found.\n", name);
28036285Sbrian      return -1;
28132403Sbrian    }
28236285Sbrian    bundle_SetLabel(arg->bundle, arg->argc > arg->argn ? name : NULL);
28336285Sbrian  }
28426516Sbrian  return 0;
2856059Samurai}
2866059Samurai
28736285Sbrianint
28836285SbrianSaveCommand(struct cmdargs const *arg)
28936285Sbrian{
29036285Sbrian  log_Printf(LogWARN, "save command is not implemented (yet).\n");
29136285Sbrian  return 1;
29236285Sbrian}
29336285Sbrian
29410528Samuraistatic int
29536285SbrianDialCommand(struct cmdargs const *arg)
29628536Sbrian{
29736285Sbrian  int res;
29836285Sbrian
29936465Sbrian  if ((arg->cx && !(arg->cx->physical->type & (PHYS_INTERACTIVE|PHYS_AUTO)))
30036465Sbrian      || (!arg->cx &&
30136465Sbrian          (arg->bundle->phys_type & ~(PHYS_INTERACTIVE|PHYS_AUTO)))) {
30236285Sbrian    log_Printf(LogWARN, "Manual dial is only available for auto and"
30336285Sbrian              " interactive links\n");
30436285Sbrian    return 1;
30534536Sbrian  }
30636285Sbrian
30736285Sbrian  if (arg->argc > arg->argn && (res = LoadCommand(arg)) != 0)
30836285Sbrian    return res;
30936285Sbrian
31036285Sbrian  bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL);
31136285Sbrian
31236285Sbrian  return 0;
31328536Sbrian}
31428536Sbrian
31528536Sbrianstatic int
31631343SbrianShellCommand(struct cmdargs const *arg, int bg)
31710528Samurai{
31810528Samurai  const char *shell;
31910528Samurai  pid_t shpid;
32031343Sbrian  int argc;
32131343Sbrian  char *argv[MAXARGS];
32220813Sjkh
32318856Ssos#ifdef SHELL_ONLY_INTERACTIVELY
32426911Sbrian  /* we're only allowed to shell when we run ppp interactively */
32536285Sbrian  if (arg->prompt && arg->prompt->owner) {
32636285Sbrian    log_Printf(LogWARN, "Can't start a shell from a network connection\n");
32726516Sbrian    return 1;
32810528Samurai  }
32926911Sbrian#endif
33028679Sbrian
33136285Sbrian  if (arg->argc == arg->argn) {
33236285Sbrian    if (!arg->prompt) {
33336285Sbrian      log_Printf(LogWARN, "Can't start an interactive shell from"
33436285Sbrian                " a config file\n");
33528381Sbrian      return 1;
33636285Sbrian    } else if (arg->prompt->owner) {
33736285Sbrian      log_Printf(LogWARN, "Can't start an interactive shell from"
33836285Sbrian                " a socket connection\n");
33936285Sbrian      return 1;
34028381Sbrian    } else if (bg) {
34136285Sbrian      log_Printf(LogWARN, "Can only start an interactive shell in"
34228679Sbrian		" the foreground mode\n");
34328381Sbrian      return 1;
34428381Sbrian    }
34534536Sbrian  }
34634536Sbrian
34728679Sbrian  if ((shpid = fork()) == 0) {
34836285Sbrian    int i, fd;
34918531Sbde
35036285Sbrian    if ((shell = getenv("SHELL")) == 0)
35136285Sbrian      shell = _PATH_BSHELL;
35232017Sbrian
35336285Sbrian    timer_TermService();
35436285Sbrian
35536285Sbrian    if (arg->prompt)
35636285Sbrian      fd = arg->prompt->fd_out;
35736285Sbrian    else if ((fd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
35836285Sbrian      log_Printf(LogALERT, "Failed to open %s: %s\n",
35936285Sbrian                _PATH_DEVNULL, strerror(errno));
36028679Sbrian      exit(1);
36128679Sbrian    }
36228679Sbrian    for (i = 0; i < 3; i++)
36328679Sbrian      dup2(fd, i);
36426516Sbrian
36536285Sbrian    fcntl(3, F_SETFD, 1);	/* Set close-on-exec flag */
36626516Sbrian
36731061Sbrian    setuid(geteuid());
36836285Sbrian    if (arg->argc > arg->argn) {
36928679Sbrian      /* substitute pseudo args */
37036285Sbrian      argv[0] = strdup(arg->argv[arg->argn]);
37136285Sbrian      for (argc = 1; argc < arg->argc - arg->argn; argc++) {
37236285Sbrian	if (strcasecmp(arg->argv[argc + arg->argn], "HISADDR") == 0)
37336285Sbrian	  argv[argc] = strdup(inet_ntoa(arg->bundle->ncp.ipcp.peer_ip));
37436285Sbrian	else if (strcasecmp(arg->argv[argc + arg->argn], "INTERFACE") == 0)
37536285Sbrian	  argv[argc] = strdup(arg->bundle->ifp.Name);
37636285Sbrian	else if (strcasecmp(arg->argv[argc + arg->argn], "MYADDR") == 0)
37736285Sbrian	  argv[argc] = strdup(inet_ntoa(arg->bundle->ncp.ipcp.my_ip));
37831343Sbrian        else
37936285Sbrian          argv[argc] = strdup(arg->argv[argc + arg->argn]);
38031343Sbrian      }
38131343Sbrian      argv[argc] = NULL;
38228679Sbrian      if (bg) {
38328679Sbrian	pid_t p;
38410528Samurai
38528679Sbrian	p = getpid();
38628679Sbrian	if (daemon(1, 1) == -1) {
38736285Sbrian	  log_Printf(LogERROR, "%d: daemon: %s\n", p, strerror(errno));
38828679Sbrian	  exit(1);
38928679Sbrian	}
39036285Sbrian      } else if (arg->prompt)
39136285Sbrian        printf("ppp: Pausing until %s finishes\n", arg->argv[arg->argn]);
39231343Sbrian      execvp(argv[0], argv);
39330316Sbrian    } else {
39436285Sbrian      if (arg->prompt)
39532017Sbrian        printf("ppp: Pausing until %s finishes\n", shell);
39636285Sbrian      prompt_TtyOldMode(arg->prompt);
39731343Sbrian      execl(shell, shell, NULL);
39830316Sbrian    }
39920813Sjkh
40036285Sbrian    log_Printf(LogWARN, "exec() of %s failed\n",
40136285Sbrian              arg->argc > arg->argn ? arg->argv[arg->argn] : shell);
40228679Sbrian    exit(255);
40310528Samurai  }
40436285Sbrian
40536285Sbrian  if (shpid == (pid_t) - 1)
40636285Sbrian    log_Printf(LogERROR, "Fork failed: %s\n", strerror(errno));
40736285Sbrian  else {
40810528Samurai    int status;
40931343Sbrian    waitpid(shpid, &status, 0);
41010528Samurai  }
41120813Sjkh
41236285Sbrian  if (arg->prompt && !arg->prompt->owner)
41336285Sbrian    prompt_TtyCommandMode(arg->prompt);
41420813Sjkh
41536285Sbrian  return 0;
41610528Samurai}
41710528Samurai
41831343Sbrianstatic int
41931343SbrianBgShellCommand(struct cmdargs const *arg)
42031343Sbrian{
42136285Sbrian  if (arg->argc == arg->argn)
42231343Sbrian    return -1;
42331343Sbrian  return ShellCommand(arg, 1);
42431343Sbrian}
42531343Sbrian
42631343Sbrianstatic int
42731343SbrianFgShellCommand(struct cmdargs const *arg)
42831343Sbrian{
42931343Sbrian  return ShellCommand(arg, 0);
43031343Sbrian}
43131343Sbrian
43230715Sbrianstatic struct cmdtab const Commands[] = {
43336285Sbrian  {"accept", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
43428679Sbrian  "accept option request", "accept option .."},
43528679Sbrian  {"add", NULL, AddCommand, LOCAL_AUTH,
43632109Sbrian  "add route", "add dest mask gateway", NULL},
43736285Sbrian  {NULL, "add!", AddCommand, LOCAL_AUTH,
43832109Sbrian  "add or change route", "add! dest mask gateway", (void *)1},
43936285Sbrian#ifndef NOALIAS
44036285Sbrian  {"alias", NULL, AliasCommand, LOCAL_AUTH,
44136285Sbrian  "alias control", "alias option [yes|no]"},
44236285Sbrian#endif
44331121Sbrian  {"allow", "auth", AllowCommand, LOCAL_AUTH,
44431121Sbrian  "Allow ppp access", "allow users|modes ...."},
44528679Sbrian  {"bg", "!bg", BgShellCommand, LOCAL_AUTH,
44631372Sbrian  "Run a background command", "[!]bg command"},
44736285Sbrian  {"clone", NULL, CloneCommand, LOCAL_AUTH | LOCAL_CX,
44836285Sbrian  "Clone a link", "clone newname..."},
44936285Sbrian  {"close", NULL, CloseCommand, LOCAL_AUTH | LOCAL_CX_OPT,
45036285Sbrian  "Close an FSM", "close [lcp|ccp]"},
45128679Sbrian  {"delete", NULL, DeleteCommand, LOCAL_AUTH,
45232109Sbrian  "delete route", "delete dest", NULL},
45336285Sbrian  {NULL, "delete!", DeleteCommand, LOCAL_AUTH,
45432109Sbrian  "delete a route if it exists", "delete! dest", (void *)1},
45536285Sbrian  {"deny", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
45628679Sbrian  "Deny option request", "deny option .."},
45736285Sbrian  {"dial", "call", DialCommand, LOCAL_AUTH | LOCAL_CX_OPT,
45828679Sbrian  "Dial and login", "dial|call [remote]"},
45936285Sbrian  {"disable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
46028679Sbrian  "Disable option", "disable option .."},
46136285Sbrian  {"down", NULL, DownCommand, LOCAL_AUTH | LOCAL_CX_OPT,
46236285Sbrian  "Generate a down event", "down"},
46336285Sbrian  {"enable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
46428679Sbrian  "Enable option", "enable option .."},
46536285Sbrian  {"link", "datalink", LinkCommand, LOCAL_AUTH,
46636285Sbrian  "Link specific commands", "link name command ..."},
46728679Sbrian  {"load", NULL, LoadCommand, LOCAL_AUTH,
46828679Sbrian  "Load settings", "load [remote]"},
46936285Sbrian  {"open", NULL, OpenCommand, LOCAL_AUTH | LOCAL_CX_OPT,
47036285Sbrian  "Open an FSM", "open [lcp|ccp]"},
47136285Sbrian  {"passwd", NULL, PasswdCommand, LOCAL_NO_AUTH,
47236285Sbrian  "Password for manipulation", "passwd LocalPassword"},
47336285Sbrian  {"quit", "bye", QuitCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
47436285Sbrian  "Quit PPP program", "quit|bye [all]"},
47536285Sbrian  {"remove", "rm", RemoveCommand, LOCAL_AUTH | LOCAL_CX,
47636285Sbrian  "Remove a link", "remove"},
47736285Sbrian  {"rename", "mv", RenameCommand, LOCAL_AUTH | LOCAL_CX,
47836285Sbrian  "Rename a link", "rename name"},
47928679Sbrian  {"save", NULL, SaveCommand, LOCAL_AUTH,
48028679Sbrian  "Save settings", "save"},
48136285Sbrian  {"set", "setup", SetCommand, LOCAL_AUTH | LOCAL_CX_OPT,
48228679Sbrian  "Set parameters", "set[up] var value"},
48328679Sbrian  {"shell", "!", FgShellCommand, LOCAL_AUTH,
48428679Sbrian  "Run a subshell", "shell|! [sh command]"},
48536285Sbrian  {"show", NULL, ShowCommand, LOCAL_AUTH | LOCAL_CX_OPT,
48631372Sbrian  "Show status and stats", "show var"},
48736285Sbrian  {"term", NULL, TerminalCommand, LOCAL_AUTH | LOCAL_CX,
48831372Sbrian  "Enter terminal mode", "term"},
48928679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
49031343Sbrian  "Display this message", "help|? [command]", Commands},
49128679Sbrian  {NULL, NULL, NULL},
4926059Samurai};
4936059Samurai
49428536Sbrianstatic int
49531343SbrianShowEscape(struct cmdargs const *arg)
4966059Samurai{
49736285Sbrian  if (arg->cx->physical->async.cfg.EscMap[32]) {
49836285Sbrian    int code, bit;
49936285Sbrian    const char *sep = "";
5006059Samurai
50126516Sbrian    for (code = 0; code < 32; code++)
50236285Sbrian      if (arg->cx->physical->async.cfg.EscMap[code])
50328679Sbrian	for (bit = 0; bit < 8; bit++)
50436285Sbrian	  if (arg->cx->physical->async.cfg.EscMap[code] & (1 << bit)) {
50536285Sbrian	    prompt_Printf(arg->prompt, "%s0x%02x", sep, (code << 3) + bit);
50636285Sbrian            sep = ", ";
50736285Sbrian          }
50836285Sbrian    prompt_Printf(arg->prompt, "\n");
5096059Samurai  }
51031077Sbrian  return 0;
5116059Samurai}
5126059Samurai
51328679Sbrianstatic int
51436285SbrianShowTimerList(struct cmdargs const *arg)
5156059Samurai{
51636285Sbrian  timer_Show(0, arg->prompt);
51731077Sbrian  return 0;
5186059Samurai}
5196059Samurai
52028679Sbrianstatic int
52131343SbrianShowStopped(struct cmdargs const *arg)
52228327Sbrian{
52336285Sbrian  prompt_Printf(arg->prompt, " Stopped Timer:  LCP: ");
52436285Sbrian  if (!arg->cx->physical->link.lcp.fsm.StoppedTimer.load)
52536285Sbrian    prompt_Printf(arg->prompt, "Disabled");
52628327Sbrian  else
52736285Sbrian    prompt_Printf(arg->prompt, "%ld secs",
52836285Sbrian                  arg->cx->physical->link.lcp.fsm.StoppedTimer.load / SECTICKS);
52928461Sbrian
53036285Sbrian  prompt_Printf(arg->prompt, ", CCP: ");
53136285Sbrian  if (!arg->cx->physical->link.ccp.fsm.StoppedTimer.load)
53236285Sbrian    prompt_Printf(arg->prompt, "Disabled");
53328461Sbrian  else
53436285Sbrian    prompt_Printf(arg->prompt, "%ld secs",
53536285Sbrian                  arg->cx->physical->link.ccp.fsm.StoppedTimer.load / SECTICKS);
53628461Sbrian
53736285Sbrian  prompt_Printf(arg->prompt, "\n");
53828461Sbrian
53931077Sbrian  return 0;
54028327Sbrian}
54128327Sbrian
54228679Sbrianstatic int
54331343SbrianShowVersion(struct cmdargs const *arg)
5446059Samurai{
54536285Sbrian  prompt_Printf(arg->prompt, "PPP Version %s - %s\n", Version, VersionDate);
54631077Sbrian  return 0;
5476059Samurai}
5486059Samurai
54928679Sbrianstatic int
55036285SbrianShowProtocolStats(struct cmdargs const *arg)
55126326Sbrian{
55236285Sbrian  struct link *l = command_ChooseLink(arg);
55326326Sbrian
55436285Sbrian  if (!l)
55536285Sbrian    return -1;
55636285Sbrian  prompt_Printf(arg->prompt, "%s:\n", l->name);
55736285Sbrian  link_ReportProtocolStatus(l, arg->prompt);
55831077Sbrian  return 0;
55926326Sbrian}
56026326Sbrian
56130715Sbrianstatic struct cmdtab const ShowCommands[] = {
56236285Sbrian  {"bundle", NULL, bundle_ShowStatus, LOCAL_AUTH,
56336285Sbrian  "bundle details", "show bundle"},
56436285Sbrian  {"ccp", NULL, ccp_ReportStatus, LOCAL_AUTH | LOCAL_CX_OPT,
56536285Sbrian  "CCP status", "show cpp"},
56636285Sbrian  {"compress", NULL, sl_Show, LOCAL_AUTH,
56736285Sbrian  "VJ compression stats", "show compress"},
56836285Sbrian  {"escape", NULL, ShowEscape, LOCAL_AUTH | LOCAL_CX,
56936285Sbrian  "escape characters", "show escape"},
57036285Sbrian  {"filter", NULL, filter_Show, LOCAL_AUTH,
57136285Sbrian  "packet filters", "show filter [in|out|dial|alive]"},
57236285Sbrian  {"hdlc", NULL, hdlc_ReportStatus, LOCAL_AUTH | LOCAL_CX,
57336285Sbrian  "HDLC errors", "show hdlc"},
57436285Sbrian  {"ipcp", NULL, ipcp_Show, LOCAL_AUTH,
57536285Sbrian  "IPCP status", "show ipcp"},
57636285Sbrian  {"lcp", NULL, lcp_ReportStatus, LOCAL_AUTH | LOCAL_CX,
57736285Sbrian  "LCP status", "show lcp"},
57836285Sbrian  {"link", "datalink", datalink_Show, LOCAL_AUTH | LOCAL_CX,
57936285Sbrian  "(high-level) link info", "show link"},
58036285Sbrian  {"links", NULL, bundle_ShowLinks, LOCAL_AUTH,
58136285Sbrian  "available link names", "show links"},
58236285Sbrian  {"log", NULL, log_ShowLevel, LOCAL_AUTH,
58336285Sbrian  "log levels", "show log"},
58436285Sbrian  {"mem", NULL, mbuf_Show, LOCAL_AUTH,
58536285Sbrian  "mbuf allocations", "show mem"},
58636285Sbrian  {"modem", NULL, modem_ShowStatus, LOCAL_AUTH | LOCAL_CX,
58736285Sbrian  "(low-level) link info", "show modem"},
58836285Sbrian  {"mp", "multilink", mp_ShowStatus, LOCAL_AUTH,
58936285Sbrian  "multilink setup", "show mp"},
59036285Sbrian  {"proto", NULL, ShowProtocolStats, LOCAL_AUTH | LOCAL_CX_OPT,
59136285Sbrian  "protocol summary", "show proto"},
59236285Sbrian  {"route", NULL, route_Show, LOCAL_AUTH,
59336285Sbrian  "routing table", "show route"},
59436285Sbrian  {"stopped", NULL, ShowStopped, LOCAL_AUTH | LOCAL_CX,
59536285Sbrian  "STOPPED timeout", "show stopped"},
59636285Sbrian  {"timers", NULL, ShowTimerList, LOCAL_AUTH,
59736285Sbrian  "alarm timers", "show timers"},
59828679Sbrian  {"version", NULL, ShowVersion, LOCAL_NO_AUTH | LOCAL_AUTH,
59936285Sbrian  "version string", "show version"},
60036285Sbrian  {"who", NULL, log_ShowWho, LOCAL_AUTH,
60136285Sbrian  "client list", "show who"},
60228679Sbrian  {"help", "?", HelpCommand, LOCAL_NO_AUTH | LOCAL_AUTH,
60331343Sbrian  "Display this message", "show help|? [command]", ShowCommands},
60428679Sbrian  {NULL, NULL, NULL},
6056059Samurai};
6066059Samurai
60730715Sbrianstatic struct cmdtab const *
60831343SbrianFindCommand(struct cmdtab const *cmds, const char *str, int *pmatch)
6096059Samurai{
61026516Sbrian  int nmatch;
61126516Sbrian  int len;
61228679Sbrian  struct cmdtab const *found;
6136059Samurai
61426516Sbrian  found = NULL;
61526516Sbrian  len = strlen(str);
61626516Sbrian  nmatch = 0;
6176059Samurai  while (cmds->func) {
61825566Sbrian    if (cmds->name && strncasecmp(str, cmds->name, len) == 0) {
61926516Sbrian      if (cmds->name[len] == '\0') {
62028679Sbrian	*pmatch = 1;
62128679Sbrian	return cmds;
62226516Sbrian      }
6236059Samurai      nmatch++;
6246059Samurai      found = cmds;
62528679Sbrian    } else if (cmds->alias && strncasecmp(str, cmds->alias, len) == 0) {
62626516Sbrian      if (cmds->alias[len] == '\0') {
62728679Sbrian	*pmatch = 1;
62828679Sbrian	return cmds;
62926516Sbrian      }
6306059Samurai      nmatch++;
6316059Samurai      found = cmds;
6326059Samurai    }
6336059Samurai    cmds++;
6346059Samurai  }
6356059Samurai  *pmatch = nmatch;
63626516Sbrian  return found;
6376059Samurai}
6386059Samurai
63936285Sbrianstatic const char *
64036285SbrianmkPrefix(int argc, char const *const *argv, char *tgt, int sz)
64136285Sbrian{
64236285Sbrian  int f, tlen, len;
64336285Sbrian
64436285Sbrian  tlen = 0;
64536285Sbrian  for (f = 0; f < argc && tlen < sz - 2; f++) {
64636285Sbrian    if (f)
64736285Sbrian      tgt[tlen++] = ' ';
64836285Sbrian    len = strlen(argv[f]);
64936285Sbrian    if (len > sz - tlen - 1)
65036285Sbrian      len = sz - tlen - 1;
65136285Sbrian    strncpy(tgt+tlen, argv[f], len);
65236285Sbrian    tlen += len;
65336285Sbrian  }
65436285Sbrian  tgt[tlen] = '\0';
65536285Sbrian  return tgt;
65636285Sbrian}
65736285Sbrian
65830715Sbrianstatic int
65936285SbrianFindExec(struct bundle *bundle, struct cmdtab const *cmds, int argc, int argn,
66036285Sbrian         char const *const *argv, struct prompt *prompt, struct datalink *cx)
6616059Samurai{
66228679Sbrian  struct cmdtab const *cmd;
6636059Samurai  int val = 1;
6646059Samurai  int nmatch;
66531343Sbrian  struct cmdargs arg;
66636285Sbrian  char prefix[100];
6676059Samurai
66836285Sbrian  cmd = FindCommand(cmds, argv[argn], &nmatch);
6696059Samurai  if (nmatch > 1)
67036285Sbrian    log_Printf(LogWARN, "%s: Ambiguous command\n",
67136285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix));
67236285Sbrian  else if (cmd && (!prompt || (cmd->lauth & prompt->auth))) {
67336285Sbrian    if ((cmd->lauth & LOCAL_CX) && !cx)
67436285Sbrian      /* We've got no context, but we require it */
67536285Sbrian      cx = bundle2datalink(bundle, NULL);
67636285Sbrian
67736285Sbrian    if ((cmd->lauth & LOCAL_CX) && !cx)
67836285Sbrian      log_Printf(LogWARN, "%s: No context (use the `link' command)\n",
67936285Sbrian                mkPrefix(argn+1, argv, prefix, sizeof prefix));
68036285Sbrian    else {
68136285Sbrian      if (cx && !(cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
68236285Sbrian        log_Printf(LogWARN, "%s: Redundant context (%s) ignored\n",
68336285Sbrian                  mkPrefix(argn+1, argv, prefix, sizeof prefix), cx->name);
68436285Sbrian        cx = NULL;
68536285Sbrian      }
68636285Sbrian      arg.cmdtab = cmds;
68736285Sbrian      arg.cmd = cmd;
68836285Sbrian      arg.argc = argc;
68936285Sbrian      arg.argn = argn+1;
69036285Sbrian      arg.argv = argv;
69136285Sbrian      arg.bundle = bundle;
69236285Sbrian      arg.cx = cx;
69336285Sbrian      arg.prompt = prompt;
69436285Sbrian      val = (*cmd->func) (&arg);
69536285Sbrian    }
69631343Sbrian  } else
69736285Sbrian    log_Printf(LogWARN, "%s: Invalid command\n",
69836285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix));
69926516Sbrian
70026516Sbrian  if (val == -1)
70136285Sbrian    log_Printf(LogWARN, "Usage: %s\n", cmd->syntax);
70228679Sbrian  else if (val)
70336285Sbrian    log_Printf(LogWARN, "%s: Failed %d\n",
70436285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix), val);
70526516Sbrian
70626516Sbrian  return val;
7076059Samurai}
7086059Samurai
7096059Samuraivoid
71036285Sbriancommand_Interpret(char *buff, int nb, int *argc, char ***argv)
7116059Samurai{
71231343Sbrian  static char *vector[MAXARGS];
7136059Samurai  char *cp;
7146059Samurai
7156059Samurai  if (nb > 0) {
7166059Samurai    cp = buff + strcspn(buff, "\r\n");
7176059Samurai    if (cp)
7186059Samurai      *cp = '\0';
71931121Sbrian    *argc = MakeArgs(buff, vector, VECSIZE(vector));
72031121Sbrian    *argv = vector;
72131121Sbrian  } else
72231121Sbrian    *argc = 0;
72331121Sbrian}
7246059Samurai
72531822Sbrianstatic int
72631822Sbrianarghidden(int argc, char const *const *argv, int n)
72731822Sbrian{
72831822Sbrian  /* Is arg n of the given command to be hidden from the log ? */
72931828Sbrian
73031828Sbrian  /* set authkey xxxxx */
73131828Sbrian  /* set key xxxxx */
73231822Sbrian  if (n == 2 && !strncasecmp(argv[0], "se", 2) &&
73331822Sbrian      (!strncasecmp(argv[1], "authk", 5) || !strncasecmp(argv[1], "ke", 2)))
73431822Sbrian    return 1;
73531822Sbrian
73631828Sbrian  /* passwd xxxxx */
73731828Sbrian  if (n == 1 && !strncasecmp(argv[0], "p", 1))
73831828Sbrian    return 1;
73931828Sbrian
74036285Sbrian  /* set server port xxxxx .... */
74136285Sbrian  if (n == 3 && !strncasecmp(argv[0], "se", 2) &&
74236285Sbrian      !strncasecmp(argv[1], "se", 2))
74336285Sbrian    return 1;
74436285Sbrian
74531822Sbrian  return 0;
74631822Sbrian}
74731822Sbrian
74831121Sbrianvoid
74936285Sbriancommand_Run(struct bundle *bundle, int argc, char const *const *argv,
75036285Sbrian           struct prompt *prompt, const char *label)
75131121Sbrian{
75231156Sbrian  if (argc > 0) {
75336285Sbrian    if (log_IsKept(LogCOMMAND)) {
75431156Sbrian      static char buf[LINE_LEN];
75531156Sbrian      int f, n;
75631156Sbrian
75731156Sbrian      *buf = '\0';
75831156Sbrian      if (label) {
75931962Sbrian        strncpy(buf, label, sizeof buf - 3);
76031962Sbrian        buf[sizeof buf - 3] = '\0';
76131156Sbrian        strcat(buf, ": ");
76231156Sbrian      }
76331156Sbrian      n = strlen(buf);
76431156Sbrian      for (f = 0; f < argc; f++) {
76531962Sbrian        if (n < sizeof buf - 1 && f)
76631156Sbrian          buf[n++] = ' ';
76731822Sbrian        if (arghidden(argc, argv, f))
76836285Sbrian          strncpy(buf+n, "********", sizeof buf - n - 1);
76931822Sbrian        else
77031962Sbrian          strncpy(buf+n, argv[f], sizeof buf - n - 1);
77131156Sbrian        n += strlen(buf+n);
77231156Sbrian      }
77336285Sbrian      log_Printf(LogCOMMAND, "%s\n", buf);
77431156Sbrian    }
77536285Sbrian    FindExec(bundle, Commands, argc, 0, argv, prompt, NULL);
77631156Sbrian  }
7776059Samurai}
7786059Samurai
77931121Sbrianvoid
78036285Sbriancommand_Decode(struct bundle *bundle, char *buff, int nb, struct prompt *prompt,
78136285Sbrian              const char *label)
78231121Sbrian{
78331121Sbrian  int argc;
78431121Sbrian  char **argv;
78531121Sbrian
78636285Sbrian  command_Interpret(buff, nb, &argc, &argv);
78736285Sbrian  command_Run(bundle, argc, (char const *const *)argv, prompt, label);
78831121Sbrian}
78931121Sbrian
7906059Samuraistatic int
79131343SbrianShowCommand(struct cmdargs const *arg)
7926059Samurai{
79336285Sbrian  if (!arg->prompt)
79436285Sbrian    log_Printf(LogWARN, "show: Cannot show without a prompt\n");
79536285Sbrian  else if (arg->argc > arg->argn)
79636285Sbrian    FindExec(arg->bundle, ShowCommands, arg->argc, arg->argn, arg->argv,
79736285Sbrian             arg->prompt, arg->cx);
7986059Samurai  else
79936285Sbrian    prompt_Printf(arg->prompt, "Use ``show ?'' to get a list.\n");
80026516Sbrian
80126516Sbrian  return 0;
8026059Samurai}
8036059Samurai
8046059Samuraistatic int
80531343SbrianTerminalCommand(struct cmdargs const *arg)
8066059Samurai{
80736285Sbrian  if (!arg->prompt) {
80836285Sbrian    log_Printf(LogWARN, "term: Need a prompt\n");
80926516Sbrian    return 1;
8106059Samurai  }
81136285Sbrian
81236285Sbrian  if (arg->cx->physical->link.lcp.fsm.state > ST_CLOSED) {
81336285Sbrian    prompt_Printf(arg->prompt, "LCP state is [%s]\n",
81436285Sbrian                  State2Nam(arg->cx->physical->link.lcp.fsm.state));
81536285Sbrian    return 1;
8166059Samurai  }
81736285Sbrian
81836285Sbrian  datalink_Up(arg->cx, 0, 0);
81936285Sbrian  prompt_TtyTermMode(arg->prompt, arg->cx);
82036285Sbrian  return 0;
8216059Samurai}
8226059Samurai
8236059Samuraistatic int
82431343SbrianQuitCommand(struct cmdargs const *arg)
8256059Samurai{
82636285Sbrian  if (!arg->prompt || prompt_IsController(arg->prompt) ||
82736285Sbrian      (arg->argc > arg->argn && !strcasecmp(arg->argv[arg->argn], "all") &&
82836285Sbrian       (arg->prompt->auth & LOCAL_AUTH)))
82936285Sbrian    Cleanup(EX_NORMAL);
83036285Sbrian  if (arg->prompt)
83136285Sbrian    prompt_Destroy(arg->prompt, 1);
83226516Sbrian
83326516Sbrian  return 0;
8346059Samurai}
8356059Samurai
8366059Samuraistatic int
83736285SbrianOpenCommand(struct cmdargs const *arg)
8386059Samurai{
83936285Sbrian  if (arg->argc == arg->argn ||
84036285Sbrian      (arg->argc == arg->argn+1 && !strcasecmp(arg->argv[arg->argn], "lcp")))
84136285Sbrian    bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL);
84236285Sbrian  else if (arg->argc == arg->argn+1 &&
84336285Sbrian           !strcasecmp(arg->argv[arg->argn], "ccp")) {
84436285Sbrian    struct link *l;
84536285Sbrian    struct fsm *fp;
8466059Samurai
84736285Sbrian    if (!(l = command_ChooseLink(arg)))
84836285Sbrian      return -1;
84936285Sbrian    fp = &l->ccp.fsm;
85036285Sbrian
85136285Sbrian    if (fp->link->lcp.fsm.state != ST_OPENED)
85236285Sbrian      log_Printf(LogWARN, "open: LCP must be open before opening CCP\n");
85336285Sbrian    else if (fp->state != ST_OPENED) {
85436285Sbrian      fp->open_mode = 0;	/* Not passive any more */
85536285Sbrian      if (fp->state == ST_STOPPED) {
85636285Sbrian        fsm_Down(fp);
85736285Sbrian        fsm_Up(fp);
85836285Sbrian      } else {
85936285Sbrian        fsm_Up(fp);
86036285Sbrian        fsm_Open(fp);
86136285Sbrian      }
86236285Sbrian    }
86336285Sbrian  } else
86436285Sbrian    return -1;
86536285Sbrian
86626516Sbrian  return 0;
8676059Samurai}
8686059Samurai
86925067Sbrianstatic int
87036285SbrianCloseCommand(struct cmdargs const *arg)
8716059Samurai{
87236285Sbrian  if (arg->argc == arg->argn ||
87336285Sbrian      (arg->argc == arg->argn+1 && !strcasecmp(arg->argv[arg->argn], "lcp")))
87436285Sbrian    bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, 1);
87536285Sbrian  else if (arg->argc == arg->argn+1 &&
87636285Sbrian           (!strcasecmp(arg->argv[arg->argn], "ccp") ||
87736285Sbrian            !strcasecmp(arg->argv[arg->argn], "ccp!"))) {
87836285Sbrian    struct link *l;
87936285Sbrian    struct fsm *fp;
8806059Samurai
88136285Sbrian    if (!(l = command_ChooseLink(arg)))
88236285Sbrian      return -1;
88336285Sbrian    fp = &l->ccp.fsm;
88436285Sbrian
88536285Sbrian    if (fp->state == ST_OPENED) {
88636285Sbrian      fsm_Close(fp);
88736285Sbrian      if (arg->argv[arg->argn][3] == '!')
88836285Sbrian        fp->open_mode = 0;		/* Stay ST_CLOSED */
88936285Sbrian      else
89036285Sbrian        fp->open_mode = OPEN_PASSIVE;	/* Wait for the peer to start */
8916735Samurai    }
89236285Sbrian  } else
89336285Sbrian    return -1;
89436285Sbrian
89536285Sbrian  return 0;
8966059Samurai}
8976059Samurai
89825067Sbrianstatic int
89936285SbrianDownCommand(struct cmdargs const *arg)
90011336Samurai{
90136285Sbrian  if (arg->argc == arg->argn ||
90236285Sbrian      (arg->argc == arg->argn+1 && !strcasecmp(arg->argv[arg->argn], "lcp"))) {
90336285Sbrian    if (arg->cx)
90436285Sbrian      datalink_Down(arg->cx, 1);
90536285Sbrian    else
90636285Sbrian      bundle_Down(arg->bundle);
90736285Sbrian  } else if (arg->argc == arg->argn+1 &&
90836285Sbrian           !strcasecmp(arg->argv[arg->argn], "ccp")) {
90936285Sbrian    struct fsm *fp = arg->cx ? &arg->cx->physical->link.ccp.fsm :
91036285Sbrian                               &arg->bundle->ncp.mp.link.ccp.fsm;
91136285Sbrian    fsm_Down(fp);
91236285Sbrian    fsm_Close(fp);
91336285Sbrian  } else
91436285Sbrian    return -1;
91536285Sbrian
91636285Sbrian  return 0;
91725067Sbrian}
91825067Sbrian
91925067Sbrianstatic int
92036285SbrianSetModemSpeed(struct cmdargs const *arg)
92125067Sbrian{
92236285Sbrian  long speed;
92336285Sbrian  char *end;
92411336Samurai
92536285Sbrian  if (arg->argc > arg->argn && *arg->argv[arg->argn]) {
92636285Sbrian    if (arg->argc > arg->argn+1) {
92736285Sbrian      log_Printf(LogWARN, "SetModemSpeed: Too many arguments");
92836285Sbrian      return -1;
92911336Samurai    }
93036285Sbrian    if (strcasecmp(arg->argv[arg->argn], "sync") == 0) {
93136285Sbrian      physical_SetSync(arg->cx->physical);
93236285Sbrian      return 0;
93336285Sbrian    }
93436285Sbrian    end = NULL;
93536285Sbrian    speed = strtol(arg->argv[arg->argn], &end, 10);
93636285Sbrian    if (*end) {
93736285Sbrian      log_Printf(LogWARN, "SetModemSpeed: Bad argument \"%s\"",
93836285Sbrian                arg->argv[arg->argn]);
93936285Sbrian      return -1;
94036285Sbrian    }
94136285Sbrian    if (physical_SetSpeed(arg->cx->physical, speed))
94236285Sbrian      return 0;
94336285Sbrian    log_Printf(LogWARN, "%s: Invalid speed\n", arg->argv[arg->argn]);
94436285Sbrian  } else
94536285Sbrian    log_Printf(LogWARN, "SetModemSpeed: No speed specified\n");
94624939Sbrian
94726516Sbrian  return -1;
94811336Samurai}
94911336Samurai
95025067Sbrianstatic int
95131343SbrianSetStoppedTimeout(struct cmdargs const *arg)
95228327Sbrian{
95336285Sbrian  struct link *l = &arg->cx->physical->link;
95436285Sbrian
95536285Sbrian  l->lcp.fsm.StoppedTimer.load = 0;
95636285Sbrian  l->ccp.fsm.StoppedTimer.load = 0;
95736285Sbrian  if (arg->argc <= arg->argn+2) {
95836285Sbrian    if (arg->argc > arg->argn) {
95936285Sbrian      l->lcp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn]) * SECTICKS;
96036285Sbrian      if (arg->argc > arg->argn+1)
96136285Sbrian        l->ccp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn+1]) * SECTICKS;
96228461Sbrian    }
96328327Sbrian    return 0;
96428327Sbrian  }
96528327Sbrian  return -1;
96628327Sbrian}
96728327Sbrian
96831081Sbrian#define ismask(x) \
96931081Sbrian  (*x == '0' && strlen(x) == 4 && strspn(x+1, "0123456789.") == 3)
97031081Sbrian
97128327Sbrianstatic int
97231343SbrianSetServer(struct cmdargs const *arg)
97326940Sbrian{
97426940Sbrian  int res = -1;
97526940Sbrian
97636285Sbrian  if (arg->argc > arg->argn && arg->argc < arg->argn+4) {
97731081Sbrian    const char *port, *passwd, *mask;
97831081Sbrian
97931081Sbrian    /* What's what ? */
98036285Sbrian    port = arg->argv[arg->argn];
98136285Sbrian    if (arg->argc == arg->argn + 2) {
98236285Sbrian      passwd = arg->argv[arg->argn+1];
98336285Sbrian      mask = NULL;
98436285Sbrian    } else if (arg->argc == arg->argn + 3) {
98536285Sbrian      passwd = arg->argv[arg->argn+1];
98636285Sbrian      mask = arg->argv[arg->argn+2];
98731081Sbrian      if (!ismask(mask))
98831081Sbrian        return -1;
98936285Sbrian    } else if (strcasecmp(port, "none") == 0) {
99036285Sbrian      if (server_Close(arg->bundle))
99136285Sbrian        log_Printf(LogPHASE, "Disabled server port.\n");
99236285Sbrian      return 0;
99331081Sbrian    } else
99436285Sbrian      return -1;
99531081Sbrian
99636285Sbrian    strncpy(server.passwd, passwd, sizeof server.passwd - 1);
99736285Sbrian    server.passwd[sizeof server.passwd - 1] = '\0';
99831081Sbrian
99936285Sbrian    if (*port == '/') {
100031081Sbrian      mode_t imask;
100136285Sbrian      char *ptr, name[LINE_LEN + 12];
100228679Sbrian
100331081Sbrian      if (mask != NULL) {
100428679Sbrian	unsigned m;
100528679Sbrian
100631081Sbrian	if (sscanf(mask, "%o", &m) == 1)
100731081Sbrian	  imask = m;
100831081Sbrian        else
100931081Sbrian          return -1;
101031081Sbrian      } else
101131081Sbrian        imask = (mode_t)-1;
101236285Sbrian
101336285Sbrian      ptr = strstr(port, "%d");
101436285Sbrian      if (ptr) {
101536285Sbrian        snprintf(name, sizeof name, "%.*s%d%s",
101636285Sbrian                 ptr - port, port, arg->bundle->unit, ptr + 2);
101736285Sbrian        port = name;
101836285Sbrian      }
101936285Sbrian      res = server_LocalOpen(arg->bundle, port, imask);
102027346Sbrian    } else {
102136285Sbrian      int iport, add = 0;
102228679Sbrian
102331081Sbrian      if (mask != NULL)
102431081Sbrian        return -1;
102528679Sbrian
102636285Sbrian      if (*port == '+') {
102736285Sbrian        port++;
102836285Sbrian        add = 1;
102936285Sbrian      }
103031081Sbrian      if (strspn(port, "0123456789") != strlen(port)) {
103131081Sbrian        struct servent *s;
103231081Sbrian
103331081Sbrian        if ((s = getservbyname(port, "tcp")) == NULL) {
103431081Sbrian	  iport = 0;
103536285Sbrian	  log_Printf(LogWARN, "%s: Invalid port or service\n", port);
103628679Sbrian	} else
103731081Sbrian	  iport = ntohs(s->s_port);
103827346Sbrian      } else
103931081Sbrian        iport = atoi(port);
104036285Sbrian
104136285Sbrian      if (iport) {
104236285Sbrian        if (add)
104336285Sbrian          iport += arg->bundle->unit;
104436285Sbrian        res = server_TcpOpen(arg->bundle, iport);
104536285Sbrian      } else
104636285Sbrian        res = -1;
104727346Sbrian    }
104831081Sbrian  }
104926940Sbrian
105026940Sbrian  return res;
105126940Sbrian}
105226940Sbrian
105326940Sbrianstatic int
105431343SbrianSetModemParity(struct cmdargs const *arg)
10556059Samurai{
105636285Sbrian  return arg->argc > arg->argn ? modem_SetParity(arg->cx->physical,
105736285Sbrian                                                 arg->argv[arg->argn]) : -1;
10586059Samurai}
10596059Samurai
10606059Samuraistatic int
106131343SbrianSetEscape(struct cmdargs const *arg)
10626059Samurai{
10636059Samurai  int code;
106436285Sbrian  int argc = arg->argc - arg->argn;
106536285Sbrian  char const *const *argv = arg->argv + arg->argn;
10666059Samurai
10676059Samurai  for (code = 0; code < 33; code++)
106836285Sbrian    arg->cx->physical->async.cfg.EscMap[code] = 0;
106931343Sbrian
10706059Samurai  while (argc-- > 0) {
10716059Samurai    sscanf(*argv++, "%x", &code);
10726059Samurai    code &= 0xff;
107336285Sbrian    arg->cx->physical->async.cfg.EscMap[code >> 3] |= (1 << (code & 7));
107436285Sbrian    arg->cx->physical->async.cfg.EscMap[32] = 1;
10756059Samurai  }
107626516Sbrian  return 0;
10776059Samurai}
10786059Samurai
107930715Sbrianstatic struct in_addr
108031343SbrianGetIpAddr(const char *cp)
10816059Samurai{
10826059Samurai  struct hostent *hp;
10836059Samurai  struct in_addr ipaddr;
10846059Samurai
108532124Sbrian  if (inet_aton(cp, &ipaddr) == 0) {
108632124Sbrian    hp = gethostbyname(cp);
108732124Sbrian    if (hp && hp->h_addrtype == AF_INET)
108832124Sbrian      memcpy(&ipaddr, hp->h_addr, hp->h_length);
108932124Sbrian    else
109032124Sbrian      ipaddr.s_addr = 0;
109132124Sbrian  }
109228679Sbrian  return (ipaddr);
10936059Samurai}
10946059Samurai
10956059Samuraistatic int
109631343SbrianSetInterfaceAddr(struct cmdargs const *arg)
10976059Samurai{
109836285Sbrian  struct ipcp *ipcp = &arg->bundle->ncp.ipcp;
109932267Sbrian  const char *hisaddr;
110032267Sbrian
110132267Sbrian  hisaddr = NULL;
110236285Sbrian  ipcp->cfg.my_range.ipaddr.s_addr = INADDR_ANY;
110336285Sbrian  ipcp->cfg.peer_range.ipaddr.s_addr = INADDR_ANY;
11046059Samurai
110536285Sbrian  if (arg->argc > arg->argn + 4)
110628679Sbrian    return -1;
110726516Sbrian
110836285Sbrian  ipcp->cfg.HaveTriggerAddress = 0;
110936285Sbrian  ipcp->cfg.netmask.s_addr = INADDR_ANY;
111036285Sbrian  iplist_reset(&ipcp->cfg.peer_list);
111128394Sbrian
111236285Sbrian  if (arg->argc > arg->argn) {
111336285Sbrian    if (!ParseAddr(ipcp, arg->argc - arg->argn, arg->argv + arg->argn,
111436285Sbrian                   &ipcp->cfg.my_range.ipaddr, &ipcp->cfg.my_range.mask,
111536285Sbrian                   &ipcp->cfg.my_range.width))
111628679Sbrian      return 1;
111736285Sbrian    if (arg->argc > arg->argn+1) {
111836285Sbrian      hisaddr = arg->argv[arg->argn+1];
111936285Sbrian      if (arg->argc > arg->argn+2) {
112036285Sbrian        ipcp->cfg.netmask = GetIpAddr(arg->argv[arg->argn+2]);
112136285Sbrian	if (arg->argc > arg->argn+3) {
112236285Sbrian	  ipcp->cfg.TriggerAddress = GetIpAddr(arg->argv[arg->argn+3]);
112336285Sbrian	  ipcp->cfg.HaveTriggerAddress = 1;
11249440Samurai	}
11256059Samurai      }
11266059Samurai    }
11276059Samurai  }
112828394Sbrian
11296059Samurai  /*
11306059Samurai   * For backwards compatibility, 0.0.0.0 means any address.
11316059Samurai   */
113236285Sbrian  if (ipcp->cfg.my_range.ipaddr.s_addr == INADDR_ANY) {
113336285Sbrian    ipcp->cfg.my_range.mask.s_addr = INADDR_ANY;
113436285Sbrian    ipcp->cfg.my_range.width = 0;
11356059Samurai  }
113636285Sbrian  ipcp->my_ip.s_addr = ipcp->cfg.my_range.ipaddr.s_addr;
113736285Sbrian
113836285Sbrian  if (ipcp->cfg.peer_range.ipaddr.s_addr == INADDR_ANY) {
113936285Sbrian    ipcp->cfg.peer_range.mask.s_addr = INADDR_ANY;
114036285Sbrian    ipcp->cfg.peer_range.width = 0;
11416059Samurai  }
114228537Sbrian
114336285Sbrian  if (hisaddr && !ipcp_UseHisaddr(arg->bundle, hisaddr,
114436465Sbrian                                  arg->bundle->phys_type & PHYS_AUTO))
114532267Sbrian    return 4;
114631121Sbrian
114726516Sbrian  return 0;
11486059Samurai}
11496059Samurai
115018752Sjkhstatic int
115131343SbrianSetVariable(struct cmdargs const *arg)
11526059Samurai{
115336285Sbrian  u_long ulong_val;
115431343Sbrian  const char *argp;
115536285Sbrian  int param = (int)arg->cmd->args, mode;
115636285Sbrian  struct datalink *cx = arg->cx;	/* LOCAL_CX uses this */
115736285Sbrian  const char *err = NULL;
115836285Sbrian  struct link *l = command_ChooseLink(arg);	/* LOCAL_CX_OPT uses this */
115936285Sbrian  int dummyint;
116036285Sbrian  struct in_addr dummyaddr, *addr;
11616059Samurai
116236285Sbrian  if (!l)
116336285Sbrian    return -1;
116436285Sbrian
116536285Sbrian  if (arg->argc > arg->argn)
116636285Sbrian    argp = arg->argv[arg->argn];
116726551Sbrian  else
116831343Sbrian    argp = "";
116926551Sbrian
117036285Sbrian  if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
117136285Sbrian    log_Printf(LogWARN, "set %s: No context (use the `link' command)\n",
117236285Sbrian              arg->cmd->name);
117336285Sbrian    return 1;
117436285Sbrian  } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
117536285Sbrian    log_Printf(LogWARN, "set %s: Redundant context (%s) ignored\n",
117636285Sbrian              arg->cmd->name, cx->name);
117736285Sbrian    cx = NULL;
117836285Sbrian  }
117936285Sbrian
118026551Sbrian  switch (param) {
118128679Sbrian  case VAR_AUTHKEY:
118236285Sbrian    if (bundle_Phase(arg->bundle) == PHASE_DEAD) {
118336285Sbrian      strncpy(arg->bundle->cfg.auth.key, argp,
118436285Sbrian              sizeof arg->bundle->cfg.auth.key - 1);
118536285Sbrian      arg->bundle->cfg.auth.key[sizeof arg->bundle->cfg.auth.key - 1] = '\0';
118636285Sbrian    } else {
118736285Sbrian      err = "set authkey: Only available at phase DEAD\n";
118836285Sbrian      log_Printf(LogWARN, err);
118936285Sbrian    }
119028679Sbrian    break;
119128679Sbrian  case VAR_AUTHNAME:
119236285Sbrian    if (bundle_Phase(arg->bundle) == PHASE_DEAD) {
119336285Sbrian      strncpy(arg->bundle->cfg.auth.name, argp,
119436285Sbrian              sizeof arg->bundle->cfg.auth.name - 1);
119536285Sbrian      arg->bundle->cfg.auth.name[sizeof arg->bundle->cfg.auth.name - 1] = '\0';
119636285Sbrian    } else {
119736285Sbrian      err = "set authname: Only available at phase DEAD\n";
119836285Sbrian      log_Printf(LogWARN, err);
119936285Sbrian    }
120028679Sbrian    break;
120136285Sbrian  case VAR_AUTOLOAD:
120236285Sbrian    if (arg->argc == arg->argn + 2 || arg->argc == arg->argn + 4) {
120336285Sbrian      arg->bundle->autoload.running = 1;
120436285Sbrian      arg->bundle->cfg.autoload.max.timeout = atoi(arg->argv[arg->argn]);
120536285Sbrian      arg->bundle->cfg.autoload.max.packets = atoi(arg->argv[arg->argn + 1]);
120636285Sbrian      if (arg->argc == arg->argn + 4) {
120736285Sbrian        arg->bundle->cfg.autoload.min.timeout = atoi(arg->argv[arg->argn + 2]);
120836285Sbrian        arg->bundle->cfg.autoload.min.packets = atoi(arg->argv[arg->argn + 3]);
120936285Sbrian      } else {
121036285Sbrian        arg->bundle->cfg.autoload.min.timeout = 0;
121136285Sbrian        arg->bundle->cfg.autoload.min.packets = 0;
121236285Sbrian      }
121336285Sbrian    } else {
121436285Sbrian      err = "Set autoload requires two or four arguments\n";
121536285Sbrian      log_Printf(LogWARN, err);
121636285Sbrian    }
121736285Sbrian    break;
121828679Sbrian  case VAR_DIAL:
121936285Sbrian    strncpy(cx->cfg.script.dial, argp, sizeof cx->cfg.script.dial - 1);
122036285Sbrian    cx->cfg.script.dial[sizeof cx->cfg.script.dial - 1] = '\0';
122128679Sbrian    break;
122228679Sbrian  case VAR_LOGIN:
122336285Sbrian    strncpy(cx->cfg.script.login, argp, sizeof cx->cfg.script.login - 1);
122436285Sbrian    cx->cfg.script.login[sizeof cx->cfg.script.login - 1] = '\0';
122528679Sbrian    break;
122636285Sbrian  case VAR_WINSIZE:
122736285Sbrian    if (arg->argc > arg->argn) {
122836285Sbrian      l->ccp.cfg.deflate.out.winsize = atoi(arg->argv[arg->argn]);
122936285Sbrian      if (l->ccp.cfg.deflate.out.winsize < 8 ||
123036285Sbrian          l->ccp.cfg.deflate.out.winsize > 15) {
123136285Sbrian          log_Printf(LogWARN, "%d: Invalid outgoing window size\n",
123236285Sbrian                    l->ccp.cfg.deflate.out.winsize);
123336285Sbrian          l->ccp.cfg.deflate.out.winsize = 15;
123436285Sbrian      }
123536285Sbrian      if (arg->argc > arg->argn+1) {
123636285Sbrian        l->ccp.cfg.deflate.in.winsize = atoi(arg->argv[arg->argn+1]);
123736285Sbrian        if (l->ccp.cfg.deflate.in.winsize < 8 ||
123836285Sbrian            l->ccp.cfg.deflate.in.winsize > 15) {
123936285Sbrian            log_Printf(LogWARN, "%d: Invalid incoming window size\n",
124036285Sbrian                      l->ccp.cfg.deflate.in.winsize);
124136285Sbrian            l->ccp.cfg.deflate.in.winsize = 15;
124236285Sbrian        }
124336285Sbrian      } else
124436285Sbrian        l->ccp.cfg.deflate.in.winsize = 0;
124536285Sbrian    } else {
124636285Sbrian      err = "No window size specified\n";
124736285Sbrian      log_Printf(LogWARN, err);
124836285Sbrian    }
124936285Sbrian    break;
125028679Sbrian  case VAR_DEVICE:
125136285Sbrian    physical_SetDeviceList(cx->physical, arg->argc - arg->argn,
125236285Sbrian                           arg->argv + arg->argn);
125336285Sbrian    break;
125436285Sbrian  case VAR_ACCMAP:
125536285Sbrian    if (arg->argc > arg->argn) {
125636285Sbrian      sscanf(argp, "%lx", &ulong_val);
125736285Sbrian      cx->physical->link.lcp.cfg.accmap = ulong_val;
125836285Sbrian    } else {
125936285Sbrian      err = "No accmap specified\n";
126036285Sbrian      log_Printf(LogWARN, err);
126136285Sbrian    }
126236285Sbrian    break;
126336285Sbrian  case VAR_MODE:
126436285Sbrian    mode = Nam2mode(argp);
126536285Sbrian    if (mode == PHYS_NONE || mode == PHYS_ALL) {
126636285Sbrian      log_Printf(LogWARN, "%s: Invalid mode\n", argp);
126736285Sbrian      return -1;
126836285Sbrian    }
126936285Sbrian    bundle_SetMode(arg->bundle, cx, mode);
127036285Sbrian    break;
127136285Sbrian  case VAR_MRRU:
127236285Sbrian    if (bundle_Phase(arg->bundle) != PHASE_DEAD)
127336285Sbrian      log_Printf(LogWARN, "mrru: Only changable at phase DEAD\n");
127429696Sbrian    else {
127536285Sbrian      ulong_val = atol(argp);
127636285Sbrian      if (ulong_val < MIN_MRU)
127736285Sbrian        err = "Given MRRU value (%lu) is too small.\n";
127836285Sbrian      else if (ulong_val > MAX_MRU)
127936285Sbrian        err = "Given MRRU value (%lu) is too big.\n";
128036285Sbrian      else
128136285Sbrian        arg->bundle->ncp.mp.cfg.mrru = ulong_val;
128236285Sbrian      if (err)
128336285Sbrian        log_Printf(LogWARN, err, ulong_val);
128429696Sbrian    }
128528679Sbrian    break;
128636285Sbrian  case VAR_MRU:
128736285Sbrian    ulong_val = atol(argp);
128836285Sbrian    if (ulong_val < MIN_MRU)
128936285Sbrian      err = "Given MRU value (%lu) is too small.\n";
129036285Sbrian    else if (ulong_val > MAX_MRU)
129136285Sbrian      err = "Given MRU value (%lu) is too big.\n";
129236285Sbrian    else
129336285Sbrian      l->lcp.cfg.mru = ulong_val;
129436285Sbrian    if (err)
129536285Sbrian      log_Printf(LogWARN, err, ulong_val);
129628679Sbrian    break;
129736285Sbrian  case VAR_MTU:
129836285Sbrian    ulong_val = atol(argp);
129936285Sbrian    if (ulong_val == 0)
130036285Sbrian      arg->bundle->cfg.mtu = 0;
130136285Sbrian    else if (ulong_val < MIN_MTU)
130236285Sbrian      err = "Given MTU value (%lu) is too small.\n";
130336285Sbrian    else if (ulong_val > MAX_MTU)
130436285Sbrian      err = "Given MTU value (%lu) is too big.\n";
130536285Sbrian    else
130636285Sbrian      arg->bundle->cfg.mtu = ulong_val;
130736285Sbrian    if (err)
130836285Sbrian      log_Printf(LogWARN, err, ulong_val);
130936285Sbrian    break;
131036285Sbrian  case VAR_OPENMODE:
131136285Sbrian    if (strcasecmp(argp, "active") == 0)
131236285Sbrian      cx->physical->link.lcp.cfg.openmode = arg->argc > arg->argn+1 ?
131336285Sbrian        atoi(arg->argv[arg->argn+1]) : 1;
131436285Sbrian    else if (strcasecmp(argp, "passive") == 0)
131536285Sbrian      cx->physical->link.lcp.cfg.openmode = OPEN_PASSIVE;
131636285Sbrian    else {
131736285Sbrian      err = "%s: Invalid openmode\n";
131836285Sbrian      log_Printf(LogWARN, err, argp);
131936285Sbrian    }
132036285Sbrian    break;
132128679Sbrian  case VAR_PHONE:
132236285Sbrian    strncpy(cx->cfg.phone.list, argp, sizeof cx->cfg.phone.list - 1);
132336285Sbrian    cx->cfg.phone.list[sizeof cx->cfg.phone.list - 1] = '\0';
132428679Sbrian    break;
132528679Sbrian  case VAR_HANGUP:
132636285Sbrian    strncpy(cx->cfg.script.hangup, argp, sizeof cx->cfg.script.hangup - 1);
132736285Sbrian    cx->cfg.script.hangup[sizeof cx->cfg.script.hangup - 1] = '\0';
132828679Sbrian    break;
132936285Sbrian  case VAR_IDLETIMEOUT:
133036285Sbrian    if (arg->argc > arg->argn+1)
133136285Sbrian      err = "Too many idle timeout values\n";
133236285Sbrian    else if (arg->argc == arg->argn+1)
133336285Sbrian      bundle_SetIdleTimer(arg->bundle, atoi(argp));
133436285Sbrian    if (err)
133536285Sbrian      log_Printf(LogWARN, err);
133629549Sbrian    break;
133736285Sbrian  case VAR_LQRPERIOD:
133836285Sbrian    ulong_val = atol(argp);
133936285Sbrian    if (ulong_val <= 0) {
134036285Sbrian      err = "%s: Invalid lqr period\n";
134136285Sbrian      log_Printf(LogWARN, err, argp);
134236285Sbrian    } else
134336285Sbrian      l->lcp.cfg.lqrperiod = ulong_val;
134436285Sbrian    break;
134536285Sbrian  case VAR_LCPRETRY:
134636285Sbrian    ulong_val = atol(argp);
134736285Sbrian    if (ulong_val <= 0) {
134836285Sbrian      err = "%s: Invalid LCP FSM retry period\n";
134936285Sbrian      log_Printf(LogWARN, err, argp);
135036285Sbrian    } else
135136285Sbrian      cx->physical->link.lcp.cfg.fsmretry = ulong_val;
135236285Sbrian    break;
135336285Sbrian  case VAR_CHAPRETRY:
135436285Sbrian    ulong_val = atol(argp);
135536285Sbrian    if (ulong_val <= 0) {
135636285Sbrian      err = "%s: Invalid CHAP retry period\n";
135736285Sbrian      log_Printf(LogWARN, err, argp);
135836285Sbrian    } else
135936285Sbrian      cx->chap.auth.cfg.fsmretry = ulong_val;
136036285Sbrian    break;
136136285Sbrian  case VAR_PAPRETRY:
136236285Sbrian    ulong_val = atol(argp);
136336285Sbrian    if (ulong_val <= 0) {
136436285Sbrian      err = "%s: Invalid PAP retry period\n";
136536285Sbrian      log_Printf(LogWARN, err, argp);
136636285Sbrian    } else
136736285Sbrian      cx->pap.cfg.fsmretry = ulong_val;
136836285Sbrian    break;
136936285Sbrian  case VAR_CCPRETRY:
137036285Sbrian    ulong_val = atol(argp);
137136285Sbrian    if (ulong_val <= 0) {
137236285Sbrian      err = "%s: Invalid CCP FSM retry period\n";
137336285Sbrian      log_Printf(LogWARN, err, argp);
137436285Sbrian    } else
137536285Sbrian      l->ccp.cfg.fsmretry = ulong_val;
137636285Sbrian    break;
137736285Sbrian  case VAR_IPCPRETRY:
137836285Sbrian    ulong_val = atol(argp);
137936285Sbrian    if (ulong_val <= 0) {
138036285Sbrian      err = "%s: Invalid IPCP FSM retry period\n";
138136285Sbrian      log_Printf(LogWARN, err, argp);
138236285Sbrian    } else
138336285Sbrian      arg->bundle->ncp.ipcp.cfg.fsmretry = ulong_val;
138436285Sbrian    break;
138536285Sbrian  case VAR_NBNS:
138636285Sbrian  case VAR_DNS:
138736285Sbrian    if (param == VAR_DNS)
138836285Sbrian      addr = arg->bundle->ncp.ipcp.cfg.ns.dns;
138936285Sbrian    else
139036285Sbrian      addr = arg->bundle->ncp.ipcp.cfg.ns.nbns;
139136285Sbrian
139236285Sbrian    addr[0].s_addr = addr[1].s_addr = INADDR_ANY;
139336285Sbrian
139436285Sbrian    if (arg->argc > arg->argn) {
139536285Sbrian      ParseAddr(&arg->bundle->ncp.ipcp, 1, arg->argv + arg->argn,
139636285Sbrian                addr, &dummyaddr, &dummyint);
139736285Sbrian      if (arg->argc > arg->argn+1)
139836285Sbrian        ParseAddr(&arg->bundle->ncp.ipcp, 1, arg->argv + arg->argn + 1,
139936285Sbrian                  addr + 1, &dummyaddr, &dummyint);
140036285Sbrian
140136285Sbrian      if (addr[1].s_addr == INADDR_ANY)
140236285Sbrian        addr[1].s_addr = addr[0].s_addr;
140336285Sbrian      if (addr[0].s_addr == INADDR_ANY)
140436285Sbrian        addr[0].s_addr = addr[1].s_addr;
140536285Sbrian    }
140636285Sbrian    break;
14076059Samurai  }
140836285Sbrian
140936285Sbrian  return err ? 1 : 0;
14106059Samurai}
14116059Samurai
141228679Sbrianstatic int
141331343SbrianSetCtsRts(struct cmdargs const *arg)
141420812Sjkh{
141536285Sbrian  if (arg->argc == arg->argn+1) {
141636285Sbrian    if (strcmp(arg->argv[arg->argn], "on") == 0)
141736285Sbrian      physical_SetRtsCts(arg->cx->physical, 1);
141836285Sbrian    else if (strcmp(arg->argv[arg->argn], "off") == 0)
141936285Sbrian      physical_SetRtsCts(arg->cx->physical, 0);
142020812Sjkh    else
142126516Sbrian      return -1;
142226516Sbrian    return 0;
142320812Sjkh  }
142426516Sbrian  return -1;
142520812Sjkh}
142620812Sjkh
142730715Sbrianstatic struct cmdtab const SetCommands[] = {
142836285Sbrian  {"accmap", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
142936285Sbrian  "accmap value", "set accmap hex-value", (const void *)VAR_ACCMAP},
143028679Sbrian  {"authkey", "key", SetVariable, LOCAL_AUTH,
143136285Sbrian  "authentication key", "set authkey|key key", (const void *)VAR_AUTHKEY},
143228679Sbrian  {"authname", NULL, SetVariable, LOCAL_AUTH,
143336285Sbrian  "authentication name", "set authname name", (const void *)VAR_AUTHNAME},
143436285Sbrian  {"autoload", NULL, SetVariable, LOCAL_AUTH,
143536285Sbrian  "auto link [de]activation", "set autoload maxtime maxload mintime minload",
143636285Sbrian  (const void *)VAR_AUTOLOAD},
143736285Sbrian  {"ccpretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
143836285Sbrian  "FSM retry period", "set ccpretry value", (const void *)VAR_CCPRETRY},
143936285Sbrian  {"chapretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
144036285Sbrian  "CHAP retry period", "set chapretry value", (const void *)VAR_CHAPRETRY},
144136285Sbrian  {"ctsrts", "crtscts", SetCtsRts, LOCAL_AUTH | LOCAL_CX,
144236285Sbrian  "Use hardware flow control", "set ctsrts [on|off]"},
144336285Sbrian  {"deflate", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
144436285Sbrian  "deflate window sizes", "set deflate out-winsize in-winsize",
144536285Sbrian  (const void *) VAR_WINSIZE},
144636285Sbrian  {"device", "line", SetVariable, LOCAL_AUTH | LOCAL_CX,
144736285Sbrian  "modem device name", "set device|line device-name[,device-name]",
144836285Sbrian  (const void *) VAR_DEVICE},
144936285Sbrian  {"dial", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
145036285Sbrian  "dialing script", "set dial chat-script", (const void *) VAR_DIAL},
145136285Sbrian  {"dns", NULL, SetVariable, LOCAL_AUTH, "Domain Name Server",
145236285Sbrian  "set dns pri-addr [sec-addr]", (const void *)VAR_DNS},
145336285Sbrian  {"enddisc", NULL, mp_SetEnddisc, LOCAL_AUTH,
145436285Sbrian  "Endpoint Discriminator", "set enddisc [IP|magic|label|psn value]"},
145536285Sbrian  {"escape", NULL, SetEscape, LOCAL_AUTH | LOCAL_CX,
145636285Sbrian  "escape characters", "set escape hex-digit ..."},
145736285Sbrian  {"filter", NULL, filter_Set, LOCAL_AUTH,
145836285Sbrian  "packet filters", "set filter alive|dial|in|out rule-no permit|deny "
145936285Sbrian  "[src_addr[/width]] [dst_addr[/width]] [tcp|udp|icmp [src [lt|eq|gt port]] "
146036285Sbrian  "[dst [lt|eq|gt port]] [estab] [syn] [finrst]]"},
146136285Sbrian  {"hangup", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
146236285Sbrian  "hangup script", "set hangup chat-script", (const void *) VAR_HANGUP},
146336285Sbrian  {"ifaddr", NULL, SetInterfaceAddr, LOCAL_AUTH, "destination address",
146431343Sbrian  "set ifaddr [src-addr [dst-addr [netmask [trg-addr]]]]"},
146536285Sbrian  {"ipcpretry", NULL, SetVariable, LOCAL_AUTH,
146636285Sbrian  "FSM retry period", "set ipcpretry value", (const void *)VAR_IPCPRETRY},
146736285Sbrian  {"lcpretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
146836285Sbrian  "FSM retry period", "set lcpretry value", (const void *)VAR_LCPRETRY},
146936285Sbrian  {"log", NULL, log_SetLevel, LOCAL_AUTH,
147036285Sbrian  "log level", "set log [local] [+|-]value..."},
147136285Sbrian  {"login", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
147236285Sbrian  "login script", "set login chat-script", (const void *) VAR_LOGIN},
147336285Sbrian  {"lqrperiod", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
147436285Sbrian  "LQR period", "set lqrperiod value", (const void *)VAR_LQRPERIOD},
147536285Sbrian  {"mode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "mode value",
147636285Sbrian  "set mode interactive|auto|ddial|background", (const void *)VAR_MODE},
147736285Sbrian  {"mrru", NULL, SetVariable, LOCAL_AUTH, "MRRU value",
147836285Sbrian  "set mrru value", (const void *)VAR_MRRU},
147936285Sbrian  {"mru", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
148036285Sbrian  "MRU value", "set mru value", (const void *)VAR_MRU},
148136285Sbrian  {"mtu", NULL, SetVariable, LOCAL_AUTH,
148236285Sbrian  "interface MTU value", "set mtu value", (const void *)VAR_MTU},
148336285Sbrian  {"nbns", NULL, SetVariable, LOCAL_AUTH, "NetBIOS Name Server",
148436285Sbrian  "set nbns pri-addr [sec-addr]", (const void *)VAR_NBNS},
148536285Sbrian  {"openmode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "open mode",
148636285Sbrian  "set openmode active|passive [secs]", (const void *)VAR_OPENMODE},
148736285Sbrian  {"papretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
148836285Sbrian  "PAP retry period", "set papretry value", (const void *)VAR_PAPRETRY},
148936285Sbrian  {"parity", NULL, SetModemParity, LOCAL_AUTH | LOCAL_CX,
149036285Sbrian  "modem parity", "set parity [odd|even|none]"},
149136285Sbrian  {"phone", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "telephone number(s)",
149236285Sbrian  "set phone phone1[:phone2[...]]", (const void *)VAR_PHONE},
149336285Sbrian  {"reconnect", NULL, datalink_SetReconnect, LOCAL_AUTH | LOCAL_CX,
149436285Sbrian  "Reconnect timeout", "set reconnect value ntries"},
149536285Sbrian  {"redial", NULL, datalink_SetRedial, LOCAL_AUTH | LOCAL_CX,
149636285Sbrian  "Redial timeout", "set redial value|random[.value|random] [attempts]"},
149728679Sbrian  {"server", "socket", SetServer, LOCAL_AUTH,
149836285Sbrian  "server port", "set server|socket TcpPort|LocalName|none [mask]"},
149936285Sbrian  {"speed", NULL, SetModemSpeed, LOCAL_AUTH | LOCAL_CX,
150036285Sbrian  "modem speed", "set speed value"},
150136285Sbrian  {"stopped", NULL, SetStoppedTimeout, LOCAL_AUTH | LOCAL_CX,
150236285Sbrian  "STOPPED timeouts", "set stopped [LCPseconds [CCPseconds]]"},
150336285Sbrian  {"timeout", NULL, SetVariable, LOCAL_AUTH, "Idle timeout",
150436285Sbrian  "set timeout idletime", (const void *)VAR_IDLETIMEOUT},
150536285Sbrian  {"vj", NULL, ipcp_vjset, LOCAL_AUTH,
150636285Sbrian  "vj values", "set vj slots|slotcomp [value]"},
150736285Sbrian  {"weight", NULL, mp_SetDatalinkWeight, LOCAL_AUTH | LOCAL_CX,
150836285Sbrian  "datalink weighting", "set weight n"},
150928679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
151031343Sbrian  "Display this message", "set help|? [command]", SetCommands},
151128679Sbrian  {NULL, NULL, NULL},
15126059Samurai};
15136059Samurai
15146059Samuraistatic int
151531343SbrianSetCommand(struct cmdargs const *arg)
15166059Samurai{
151736285Sbrian  if (arg->argc > arg->argn)
151836285Sbrian    FindExec(arg->bundle, SetCommands, arg->argc, arg->argn, arg->argv,
151936285Sbrian             arg->prompt, arg->cx);
152036285Sbrian  else if (arg->prompt)
152136285Sbrian    prompt_Printf(arg->prompt, "Use `set ?' to get a list or `set ? <var>' for"
152226516Sbrian	    " syntax help.\n");
15236059Samurai  else
152436285Sbrian    log_Printf(LogWARN, "set command must have arguments\n");
152526516Sbrian
152626516Sbrian  return 0;
15276059Samurai}
15286059Samurai
15296059Samurai
15306059Samuraistatic int
153131343SbrianAddCommand(struct cmdargs const *arg)
15326059Samurai{
15336059Samurai  struct in_addr dest, gateway, netmask;
153436285Sbrian  int gw, addrs;
15356059Samurai
153636285Sbrian  if (arg->argc != arg->argn+3 && arg->argc != arg->argn+2)
153731598Sbrian    return -1;
153831598Sbrian
153936285Sbrian  addrs = 0;
154036285Sbrian  if (arg->argc == arg->argn+2) {
154136285Sbrian    if (!strcasecmp(arg->argv[arg->argn], "default"))
154236285Sbrian      dest.s_addr = netmask.s_addr = INADDR_ANY;
154331598Sbrian    else {
154436285Sbrian      int width;
154536285Sbrian
154636285Sbrian      if (!ParseAddr(&arg->bundle->ncp.ipcp, 1, arg->argv + arg->argn,
154736285Sbrian	             &dest, &netmask, &width))
154836285Sbrian        return -1;
154936285Sbrian      if (!strncasecmp(arg->argv[arg->argn], "MYADDR", 6))
155036285Sbrian        addrs = ROUTE_DSTMYADDR;
155136285Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "HISADDR", 7))
155236285Sbrian        addrs = ROUTE_DSTHISADDR;
155331598Sbrian    }
155436285Sbrian    gw = 1;
155534536Sbrian  } else {
155636285Sbrian    if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
155736285Sbrian      addrs = ROUTE_DSTMYADDR;
155836285Sbrian      dest = arg->bundle->ncp.ipcp.my_ip;
155936285Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
156036285Sbrian      addrs = ROUTE_DSTHISADDR;
156136285Sbrian      dest = arg->bundle->ncp.ipcp.peer_ip;
156236285Sbrian    } else
156336285Sbrian      dest = GetIpAddr(arg->argv[arg->argn]);
156436285Sbrian    netmask = GetIpAddr(arg->argv[arg->argn+1]);
156531598Sbrian    gw = 2;
15666059Samurai  }
156736285Sbrian
156836285Sbrian  if (strcasecmp(arg->argv[arg->argn+gw], "HISADDR") == 0) {
156936285Sbrian    gateway = arg->bundle->ncp.ipcp.peer_ip;
157036285Sbrian    addrs |= ROUTE_GWHISADDR;
157136285Sbrian  } else if (strcasecmp(arg->argv[arg->argn+gw], "INTERFACE") == 0)
157231598Sbrian    gateway.s_addr = INADDR_ANY;
157331598Sbrian  else
157436285Sbrian    gateway = GetIpAddr(arg->argv[arg->argn+gw]);
157536285Sbrian
157636285Sbrian  if (bundle_SetRoute(arg->bundle, RTM_ADD, dest, gateway, netmask,
157736285Sbrian                  arg->cmd->args ? 1 : 0))
157836285Sbrian    route_Add(&arg->bundle->ncp.ipcp.route, addrs, dest, netmask, gateway);
157936285Sbrian
158031598Sbrian  return 0;
15816059Samurai}
15826059Samurai
15836059Samuraistatic int
158431343SbrianDeleteCommand(struct cmdargs const *arg)
15856059Samurai{
158631598Sbrian  struct in_addr dest, none;
158736285Sbrian  int addrs;
15886059Samurai
158936285Sbrian  if (arg->argc == arg->argn+1) {
159036285Sbrian    if(strcasecmp(arg->argv[arg->argn], "all") == 0) {
159136285Sbrian      route_IfDelete(arg->bundle, 0);
159236285Sbrian      route_DeleteAll(&arg->bundle->ncp.ipcp.route);
159336285Sbrian    } else {
159436285Sbrian      addrs = 0;
159536285Sbrian      if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
159636285Sbrian        dest = arg->bundle->ncp.ipcp.my_ip;
159736285Sbrian        addrs = ROUTE_DSTMYADDR;
159836285Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
159936285Sbrian        dest = arg->bundle->ncp.ipcp.peer_ip;
160036285Sbrian        addrs = ROUTE_DSTHISADDR;
160136285Sbrian      } else {
160236285Sbrian        if (strcasecmp(arg->argv[arg->argn], "default") == 0)
160336285Sbrian          dest.s_addr = INADDR_ANY;
160436285Sbrian        else
160536285Sbrian          dest = GetIpAddr(arg->argv[arg->argn]);
160636285Sbrian        addrs = ROUTE_STATIC;
160736285Sbrian      }
160831598Sbrian      none.s_addr = INADDR_ANY;
160936285Sbrian      bundle_SetRoute(arg->bundle, RTM_DELETE, dest, none, none,
161036285Sbrian                      arg->cmd->args ? 1 : 0);
161136285Sbrian      route_Delete(&arg->bundle->ncp.ipcp.route, addrs, dest);
161231598Sbrian    }
161334536Sbrian  } else
161426516Sbrian    return -1;
161526516Sbrian
161626516Sbrian  return 0;
16176059Samurai}
16186059Samurai
161931343Sbrian#ifndef NOALIAS
162026031Sbrianstatic struct cmdtab const AliasCommands[] =
162126031Sbrian{
162236285Sbrian  {"addr", NULL, alias_RedirectAddr, LOCAL_AUTH,
162336285Sbrian   "static address translation", "alias addr [addr_local addr_alias]"},
162436285Sbrian  {"deny_incoming", NULL, AliasOption, LOCAL_AUTH,
162536285Sbrian   "stop incoming connections", "alias deny_incoming [yes|no]",
162636285Sbrian   (const void *) PKT_ALIAS_DENY_INCOMING},
162728679Sbrian  {"enable", NULL, AliasEnable, LOCAL_AUTH,
162836285Sbrian   "enable IP aliasing", "alias enable [yes|no]"},
162928679Sbrian  {"log", NULL, AliasOption, LOCAL_AUTH,
163036285Sbrian   "log aliasing link creation", "alias log [yes|no]",
163136285Sbrian   (const void *) PKT_ALIAS_LOG},
163236285Sbrian  {"port", NULL, alias_RedirectPort, LOCAL_AUTH,
163336285Sbrian   "port redirection", "alias port [proto addr_local:port_local  port_alias]"},
163428679Sbrian  {"same_ports", NULL, AliasOption, LOCAL_AUTH,
163536285Sbrian   "try to leave port numbers unchanged", "alias same_ports [yes|no]",
163636285Sbrian   (const void *) PKT_ALIAS_SAME_PORTS},
163736285Sbrian  {"unregistered_only", NULL, AliasOption, LOCAL_AUTH,
163836285Sbrian   "alias unregistered (private) IP address space only",
163936285Sbrian   "alias unregistered_only [yes|no]",
164036285Sbrian   (const void *) PKT_ALIAS_UNREGISTERED_ONLY},
164128679Sbrian  {"use_sockets", NULL, AliasOption, LOCAL_AUTH,
164236285Sbrian   "allocate host sockets", "alias use_sockets [yes|no]",
164336285Sbrian   (const void *) PKT_ALIAS_USE_SOCKETS},
164428679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
164536285Sbrian   "Display this message", "alias help|? [command]", AliasCommands},
164628679Sbrian  {NULL, NULL, NULL},
164726031Sbrian};
164826031Sbrian
164926031Sbrian
165026031Sbrianstatic int
165131343SbrianAliasCommand(struct cmdargs const *arg)
165226031Sbrian{
165336285Sbrian  if (arg->argc > arg->argn)
165436285Sbrian    FindExec(arg->bundle, AliasCommands, arg->argc, arg->argn, arg->argv,
165536285Sbrian             arg->prompt, arg->cx);
165636285Sbrian  else if (arg->prompt)
165736285Sbrian    prompt_Printf(arg->prompt, "Use `alias help' to get a list or `alias help"
165836285Sbrian            " <option>' for syntax help.\n");
165926031Sbrian  else
166036285Sbrian    log_Printf(LogWARN, "alias command must have arguments\n");
166126516Sbrian
166226516Sbrian  return 0;
166326031Sbrian}
166426031Sbrian
166526031Sbrianstatic int
166631343SbrianAliasEnable(struct cmdargs const *arg)
166726031Sbrian{
166836285Sbrian  if (arg->argc == arg->argn+1) {
166936285Sbrian    if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
167036285Sbrian      if (alias_Load() == 0)
167136285Sbrian	return 0;
167236285Sbrian      log_Printf(LogWARN, "Cannot load alias library\n");
167336285Sbrian      return 1;
167436285Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "no") == 0) {
167536285Sbrian      alias_Unload();
167626516Sbrian      return 0;
167726142Sbrian    }
167835449Sbrian  }
167936285Sbrian
168026516Sbrian  return -1;
168126031Sbrian}
168226031Sbrian
168326031Sbrian
168426031Sbrianstatic int
168531343SbrianAliasOption(struct cmdargs const *arg)
168626031Sbrian{
168736285Sbrian  unsigned param = (unsigned)arg->cmd->args;
168836285Sbrian  if (arg->argc == arg->argn+1) {
168936285Sbrian    if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
169036285Sbrian      if (alias_IsEnabled()) {
169136285Sbrian	(*PacketAlias.SetMode)(param, param);
169228679Sbrian	return 0;
169328679Sbrian      }
169436285Sbrian      log_Printf(LogWARN, "alias not enabled\n");
169536285Sbrian    } else if (strcmp(arg->argv[arg->argn], "no") == 0) {
169636285Sbrian      if (alias_IsEnabled()) {
169736285Sbrian	(*PacketAlias.SetMode)(0, param);
169828679Sbrian	return 0;
169928679Sbrian      }
170036285Sbrian      log_Printf(LogWARN, "alias not enabled\n");
170128679Sbrian    }
170235449Sbrian  }
170328679Sbrian  return -1;
170426031Sbrian}
170531343Sbrian#endif /* #ifndef NOALIAS */
170631121Sbrian
170731121Sbrianstatic struct cmdtab const AllowCommands[] = {
170836285Sbrian  {"modes", "mode", AllowModes, LOCAL_AUTH,
170936285Sbrian  "Only allow certain ppp modes", "allow modes mode..."},
171031121Sbrian  {"users", "user", AllowUsers, LOCAL_AUTH,
171131121Sbrian  "Allow users access to ppp", "allow users logname..."},
171231121Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
171331343Sbrian  "Display this message", "allow help|? [command]", AllowCommands},
171431121Sbrian  {NULL, NULL, NULL},
171531121Sbrian};
171631121Sbrian
171731121Sbrianstatic int
171831343SbrianAllowCommand(struct cmdargs const *arg)
171931121Sbrian{
172036285Sbrian  /* arg->bundle may be NULL (see system_IsValid()) ! */
172136285Sbrian  if (arg->argc > arg->argn)
172236285Sbrian    FindExec(arg->bundle, AllowCommands, arg->argc, arg->argn, arg->argv,
172336285Sbrian             arg->prompt, arg->cx);
172436285Sbrian  else if (arg->prompt)
172536285Sbrian    prompt_Printf(arg->prompt, "Use `allow ?' to get a list or `allow ? <cmd>'"
172636285Sbrian                  " for syntax help.\n");
172731121Sbrian  else
172836285Sbrian    log_Printf(LogWARN, "allow command must have arguments\n");
172931121Sbrian
173031121Sbrian  return 0;
173131121Sbrian}
173236285Sbrian
173336285Sbrianstatic int
173436285SbrianLinkCommand(struct cmdargs const *arg)
173536285Sbrian{
173636285Sbrian  if (arg->argc > arg->argn+1) {
173736285Sbrian    char namelist[LINE_LEN];
173836285Sbrian    struct datalink *cx;
173936285Sbrian    char *name;
174036285Sbrian    int result = 0;
174136285Sbrian
174236285Sbrian    if (!strcmp(arg->argv[arg->argn], "*")) {
174336285Sbrian      struct datalink *dl;
174436285Sbrian
174536285Sbrian      cx = arg->bundle->links;
174636285Sbrian      while (cx) {
174736285Sbrian        /* Watch it, the command could be a ``remove'' */
174836285Sbrian        dl = cx->next;
174936285Sbrian        FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
175036285Sbrian                 arg->prompt, cx);
175136285Sbrian        for (cx = arg->bundle->links; cx; cx = cx->next)
175236285Sbrian          if (cx == dl)
175336285Sbrian            break;		/* Pointer's still valid ! */
175436285Sbrian      }
175536285Sbrian    } else {
175636285Sbrian      strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
175736285Sbrian      namelist[sizeof namelist - 1] = '\0';
175836285Sbrian      for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
175936285Sbrian        if (!bundle2datalink(arg->bundle, name)) {
176036285Sbrian          log_Printf(LogWARN, "link: %s: Invalid link name\n", name);
176136285Sbrian          return 1;
176236285Sbrian        }
176336285Sbrian
176436285Sbrian      strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
176536285Sbrian      namelist[sizeof namelist - 1] = '\0';
176636285Sbrian      for(name = strtok(namelist, ", "); name; name = strtok(NULL,", ")) {
176736285Sbrian        cx = bundle2datalink(arg->bundle, name);
176836285Sbrian        if (cx)
176936285Sbrian          FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
177036285Sbrian                   arg->prompt, cx);
177136285Sbrian        else {
177236285Sbrian          log_Printf(LogWARN, "link: %s: Invalidated link name !\n", name);
177336285Sbrian          result++;
177436285Sbrian        }
177536285Sbrian      }
177636285Sbrian    }
177736285Sbrian    return result;
177836285Sbrian  }
177936285Sbrian
178036285Sbrian  log_Printf(LogWARN, "Usage: %s\n", arg->cmd->syntax);
178136285Sbrian  return 2;
178236285Sbrian}
178336285Sbrian
178436285Sbrianstruct link *
178536285Sbriancommand_ChooseLink(struct cmdargs const *arg)
178636285Sbrian{
178736285Sbrian  if (arg->cx)
178836285Sbrian    return &arg->cx->physical->link;
178936285Sbrian  else if (arg->bundle->ncp.mp.cfg.mrru)
179036285Sbrian    return &arg->bundle->ncp.mp.link;
179136285Sbrian  else {
179236285Sbrian    struct datalink *dl = bundle2datalink(arg->bundle, NULL);
179336285Sbrian    return dl ? &dl->physical->link : NULL;
179436285Sbrian  }
179536285Sbrian}
179636285Sbrian
179736285Sbrianstatic const char *
179836285Sbrianident_cmd(const char *cmd, unsigned *keep, unsigned *add)
179936285Sbrian{
180036285Sbrian  const char *result;
180136285Sbrian
180236285Sbrian  switch (*cmd) {
180336285Sbrian    case 'A':
180436285Sbrian    case 'a':
180536285Sbrian      result = "accept";
180636285Sbrian      *keep = NEG_MYMASK;
180736285Sbrian      *add = NEG_ACCEPTED;
180836285Sbrian      break;
180936285Sbrian    case 'D':
181036285Sbrian    case 'd':
181136285Sbrian      switch (cmd[1]) {
181236285Sbrian        case 'E':
181336285Sbrian        case 'e':
181436285Sbrian          result = "deny";
181536285Sbrian          *keep = NEG_MYMASK;
181636285Sbrian          *add = 0;
181736285Sbrian          break;
181836285Sbrian        case 'I':
181936285Sbrian        case 'i':
182036285Sbrian          result = "disable";
182136285Sbrian          *keep = NEG_HISMASK;
182236285Sbrian          *add = 0;
182336285Sbrian          break;
182436285Sbrian        default:
182536285Sbrian          return NULL;
182636285Sbrian      }
182736285Sbrian      break;
182836285Sbrian    case 'E':
182936285Sbrian    case 'e':
183036285Sbrian      result = "enable";
183136285Sbrian      *keep = NEG_HISMASK;
183236285Sbrian      *add = NEG_ENABLED;
183336285Sbrian      break;
183436285Sbrian    default:
183536285Sbrian      return NULL;
183636285Sbrian  }
183736285Sbrian
183836285Sbrian  return result;
183936285Sbrian}
184036285Sbrian
184136285Sbrianstatic int
184236285SbrianOptSet(struct cmdargs const *arg)
184336285Sbrian{
184436285Sbrian  int bit = (int)arg->cmd->args;
184536285Sbrian  const char *cmd;
184636285Sbrian  unsigned keep;			/* Keep these bits */
184736285Sbrian  unsigned add;				/* Add these bits */
184836285Sbrian
184936285Sbrian  if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL)
185036285Sbrian    return 1;
185136285Sbrian
185236285Sbrian  if (add)
185336285Sbrian    arg->bundle->cfg.opt |= bit;
185436285Sbrian  else
185536285Sbrian    arg->bundle->cfg.opt &= ~bit;
185636285Sbrian  return 0;
185736285Sbrian}
185836285Sbrian
185936285Sbrianstatic int
186036285SbrianNegotiateSet(struct cmdargs const *arg)
186136285Sbrian{
186236285Sbrian  int param = (int)arg->cmd->args;
186336285Sbrian  struct link *l = command_ChooseLink(arg);	/* LOCAL_CX_OPT uses this */
186436285Sbrian  struct datalink *cx = arg->cx;	/* LOCAL_CX uses this */
186536285Sbrian  const char *cmd;
186636285Sbrian  unsigned keep;			/* Keep these bits */
186736285Sbrian  unsigned add;				/* Add these bits */
186836285Sbrian
186936285Sbrian  if (!l)
187036285Sbrian    return -1;
187136285Sbrian
187236285Sbrian  if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL)
187336285Sbrian    return 1;
187436285Sbrian
187536285Sbrian  if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
187636285Sbrian    log_Printf(LogWARN, "%s %s: No context (use the `link' command)\n",
187736285Sbrian              cmd, arg->cmd->name);
187836285Sbrian    return 2;
187936285Sbrian  } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
188036285Sbrian    log_Printf(LogWARN, "%s %s: Redundant context (%s) ignored\n",
188136285Sbrian              cmd, arg->cmd->name, cx->name);
188236285Sbrian    cx = NULL;
188336285Sbrian  }
188436285Sbrian
188536285Sbrian  switch (param) {
188636285Sbrian    case NEG_ACFCOMP:
188736285Sbrian      cx->physical->link.lcp.cfg.acfcomp &= keep;
188836285Sbrian      cx->physical->link.lcp.cfg.acfcomp |= add;
188936285Sbrian      break;
189036285Sbrian    case NEG_CHAP:
189136285Sbrian      cx->physical->link.lcp.cfg.chap &= keep;
189236285Sbrian      cx->physical->link.lcp.cfg.chap |= add;
189336285Sbrian      break;
189436285Sbrian    case NEG_DEFLATE:
189536285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE] &= keep;
189636285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE] |= add;
189736285Sbrian      break;
189836285Sbrian    case NEG_DNS:
189936285Sbrian      arg->bundle->ncp.ipcp.cfg.ns.dns_neg &= keep;
190036285Sbrian      arg->bundle->ncp.ipcp.cfg.ns.dns_neg |= add;
190136285Sbrian      break;
190236285Sbrian    case NEG_LQR:
190336285Sbrian      cx->physical->link.lcp.cfg.lqr &= keep;
190436285Sbrian      cx->physical->link.lcp.cfg.lqr |= add;
190536285Sbrian      break;
190636285Sbrian    case NEG_PAP:
190736285Sbrian      cx->physical->link.lcp.cfg.pap &= keep;
190836285Sbrian      cx->physical->link.lcp.cfg.pap |= add;
190936285Sbrian      break;
191036285Sbrian    case NEG_PPPDDEFLATE:
191136285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE24] &= keep;
191236285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE24] |= add;
191336285Sbrian      break;
191436285Sbrian    case NEG_PRED1:
191536285Sbrian      l->ccp.cfg.neg[CCP_NEG_PRED1] &= keep;
191636285Sbrian      l->ccp.cfg.neg[CCP_NEG_PRED1] |= add;
191736285Sbrian      break;
191836285Sbrian    case NEG_PROTOCOMP:
191936285Sbrian      cx->physical->link.lcp.cfg.protocomp &= keep;
192036285Sbrian      cx->physical->link.lcp.cfg.protocomp |= add;
192136285Sbrian      break;
192236285Sbrian    case NEG_SHORTSEQ:
192336285Sbrian      if (bundle_Phase(arg->bundle) != PHASE_DEAD)
192436285Sbrian        log_Printf(LogWARN, "shortseq: Only changable at phase DEAD\n");
192536285Sbrian      else {
192636285Sbrian        arg->bundle->ncp.mp.cfg.shortseq &= keep;
192736285Sbrian        arg->bundle->ncp.mp.cfg.shortseq |= add;
192836285Sbrian      }
192936285Sbrian      break;
193036285Sbrian    case NEG_VJCOMP:
193136285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.neg &= keep;
193236285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.neg |= add;
193336285Sbrian      break;
193436285Sbrian  }
193536285Sbrian
193636285Sbrian  return 0;
193736285Sbrian}
193836285Sbrian
193936285Sbrianstatic struct cmdtab const NegotiateCommands[] = {
194036285Sbrian  {"idcheck", NULL, OptSet, LOCAL_AUTH, "Check FSM reply ids",
194136285Sbrian  "disable|enable", (const void *)OPT_IDCHECK},
194236285Sbrian  {"loopback", NULL, OptSet, LOCAL_AUTH, "Loop packets for local iface",
194336285Sbrian  "disable|enable", (const void *)OPT_LOOPBACK},
194436285Sbrian  {"passwdauth", NULL, OptSet, LOCAL_AUTH, "Use passwd file",
194536285Sbrian  "disable|enable", (const void *)OPT_PASSWDAUTH},
194636285Sbrian  {"proxy", NULL, OptSet, LOCAL_AUTH, "Create proxy ARP entry",
194736285Sbrian  "disable|enable", (const void *)OPT_PROXY},
194836285Sbrian  {"sroutes", NULL, OptSet, LOCAL_AUTH, "Use sticky routes",
194936285Sbrian  "disable|enable", (const void *)OPT_SROUTES},
195036285Sbrian  {"throughput", NULL, OptSet, LOCAL_AUTH, "Rolling throughput",
195136285Sbrian  "disable|enable", (const void *)OPT_THROUGHPUT},
195236285Sbrian  {"utmp", NULL, OptSet, LOCAL_AUTH, "Log connections in utmp",
195336285Sbrian  "disable|enable", (const void *)OPT_UTMP},
195436285Sbrian
195536285Sbrian#define OPT_MAX 7	/* accept/deny allowed below and not above */
195636285Sbrian
195736285Sbrian  {"acfcomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
195836285Sbrian  "Address & Control field compression", "accept|deny|disable|enable",
195936285Sbrian  (const void *)NEG_ACFCOMP},
196036285Sbrian  {"chap", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
196136285Sbrian  "Challenge Handshake Authentication Protocol", "accept|deny|disable|enable",
196236285Sbrian  (const void *)NEG_CHAP},
196336285Sbrian  {"deflate", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
196436285Sbrian  "Deflate compression", "accept|deny|disable|enable",
196536285Sbrian  (const void *)NEG_DEFLATE},
196636285Sbrian  {"deflate24", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
196736285Sbrian  "Deflate (type 24) compression", "accept|deny|disable|enable",
196836285Sbrian  (const void *)NEG_PPPDDEFLATE},
196936285Sbrian  {"dns", NULL, NegotiateSet, LOCAL_AUTH,
197036285Sbrian  "DNS specification", "accept|deny|disable|enable", (const void *)NEG_DNS},
197136285Sbrian  {"lqr", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
197236285Sbrian  "Link Quality Reports", "accept|deny|disable|enable",
197336285Sbrian  (const void *)NEG_LQR},
197436285Sbrian  {"pap", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
197536285Sbrian  "Password Authentication protocol", "accept|deny|disable|enable",
197636285Sbrian  (const void *)NEG_PAP},
197736285Sbrian  {"pred1", "predictor1", NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
197836285Sbrian  "Predictor 1 compression", "accept|deny|disable|enable",
197936285Sbrian  (const void *)NEG_PRED1},
198036285Sbrian  {"protocomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
198136285Sbrian  "Protocol field compression", "accept|deny|disable|enable",
198236285Sbrian  (const void *)NEG_PROTOCOMP},
198336285Sbrian  {"shortseq", NULL, NegotiateSet, LOCAL_AUTH,
198436285Sbrian  "MP Short Sequence Numbers", "accept|deny|disable|enable",
198536285Sbrian  (const void *)NEG_SHORTSEQ},
198636285Sbrian  {"vjcomp", NULL, NegotiateSet, LOCAL_AUTH,
198736285Sbrian  "Van Jacobson header compression", "accept|deny|disable|enable",
198836285Sbrian  (const void *)NEG_VJCOMP},
198936285Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
199036285Sbrian  "Display this message", "accept|deny|disable|enable help|? [value]",
199136285Sbrian  NegotiateCommands},
199236285Sbrian  {NULL, NULL, NULL},
199336285Sbrian};
199436285Sbrian
199536285Sbrianstatic int
199636285SbrianNegotiateCommand(struct cmdargs const *arg)
199736285Sbrian{
199836285Sbrian  if (arg->argc > arg->argn) {
199936285Sbrian    char const *argv[3];
200036285Sbrian    unsigned keep, add;
200136285Sbrian    int n;
200236285Sbrian
200336285Sbrian    if ((argv[0] = ident_cmd(arg->argv[arg->argn-1], &keep, &add)) == NULL)
200436285Sbrian      return -1;
200536285Sbrian    argv[2] = NULL;
200636285Sbrian
200736285Sbrian    for (n = arg->argn; n < arg->argc; n++) {
200836285Sbrian      argv[1] = arg->argv[n];
200936285Sbrian      FindExec(arg->bundle, NegotiateCommands + (keep == NEG_HISMASK ?
201036285Sbrian               0 : OPT_MAX), 2, 1, argv, arg->prompt, arg->cx);
201136285Sbrian    }
201236285Sbrian  } else if (arg->prompt)
201336285Sbrian    prompt_Printf(arg->prompt, "Use `%s ?' to get a list.\n",
201436285Sbrian	    arg->argv[arg->argn-1]);
201536285Sbrian  else
201636285Sbrian    log_Printf(LogWARN, "%s command must have arguments\n",
201736285Sbrian              arg->argv[arg->argn] );
201836285Sbrian
201936285Sbrian  return 0;
202036285Sbrian}
202136285Sbrian
202236285Sbrianconst char *
202336285Sbriancommand_ShowNegval(unsigned val)
202436285Sbrian{
202536285Sbrian  switch (val&3) {
202636285Sbrian    case 1: return "disabled & accepted";
202736285Sbrian    case 2: return "enabled & denied";
202836285Sbrian    case 3: return "enabled & accepted";
202936285Sbrian  }
203036285Sbrian  return "disabled & denied";
203136285Sbrian}
2032