command.c revision 40482
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 *
2040482Sbrian * $Id: command.c,v 1.166 1998/09/17 00:45:26 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
3338628Sbrian#include <ctype.h>
3430715Sbrian#include <errno.h>
3526516Sbrian#include <fcntl.h>
3630715Sbrian#include <paths.h>
3730715Sbrian#include <stdio.h>
3830715Sbrian#include <stdlib.h>
3930715Sbrian#include <string.h>
4030715Sbrian#include <sys/wait.h>
4130715Sbrian#include <termios.h>
4230715Sbrian#include <unistd.h>
4330715Sbrian
4439395Sbrian#ifndef NOALIAS
4539395Sbrian#ifdef __OpenBSD__
4639395Sbrian#include "alias.h"
4739395Sbrian#else
4839395Sbrian#include <alias.h>
4939395Sbrian#endif
5039395Sbrian#endif
5137009Sbrian#include "defs.h"
5231343Sbrian#include "command.h"
5330715Sbrian#include "mbuf.h"
5430715Sbrian#include "log.h"
5530715Sbrian#include "timer.h"
566059Samurai#include "fsm.h"
576059Samurai#include "lcp.h"
5831690Sbrian#include "iplist.h"
5936285Sbrian#include "throughput.h"
6036285Sbrian#include "slcompress.h"
6138557Sbrian#include "lqr.h"
6238557Sbrian#include "hdlc.h"
636059Samurai#include "ipcp.h"
646059Samurai#include "modem.h"
6531343Sbrian#ifndef NOALIAS
6626031Sbrian#include "alias_cmd.h"
6731343Sbrian#endif
6825630Sbrian#include "systems.h"
6936285Sbrian#include "filter.h"
7036285Sbrian#include "descriptor.h"
7130715Sbrian#include "main.h"
7230715Sbrian#include "route.h"
7330715Sbrian#include "ccp.h"
7431080Sbrian#include "auth.h"
7536285Sbrian#include "async.h"
7636285Sbrian#include "link.h"
7736285Sbrian#include "physical.h"
7836285Sbrian#include "mp.h"
7936285Sbrian#include "bundle.h"
8036285Sbrian#include "server.h"
8136285Sbrian#include "prompt.h"
8236285Sbrian#include "chat.h"
8336285Sbrian#include "chap.h"
8438174Sbrian#include "cbcp.h"
8536285Sbrian#include "datalink.h"
866059Samurai
8736285Sbrian/* ``set'' values */
8836285Sbrian#define	VAR_AUTHKEY	0
8936285Sbrian#define	VAR_DIAL	1
9036285Sbrian#define	VAR_LOGIN	2
9136285Sbrian#define	VAR_AUTHNAME	3
9236285Sbrian#define	VAR_AUTOLOAD	4
9336285Sbrian#define	VAR_WINSIZE	5
9436285Sbrian#define	VAR_DEVICE	6
9536285Sbrian#define	VAR_ACCMAP	7
9636285Sbrian#define	VAR_MRRU	8
9736285Sbrian#define	VAR_MRU		9
9836285Sbrian#define	VAR_MTU		10
9936285Sbrian#define	VAR_OPENMODE	11
10036285Sbrian#define	VAR_PHONE	12
10136285Sbrian#define	VAR_HANGUP	13
10236285Sbrian#define	VAR_IDLETIMEOUT	14
10336285Sbrian#define	VAR_LQRPERIOD	15
10436285Sbrian#define	VAR_LCPRETRY	16
10536285Sbrian#define	VAR_CHAPRETRY	17
10636285Sbrian#define	VAR_PAPRETRY	18
10736285Sbrian#define	VAR_CCPRETRY	19
10836285Sbrian#define	VAR_IPCPRETRY	20
10936285Sbrian#define	VAR_DNS		21
11036285Sbrian#define	VAR_NBNS	22
11136285Sbrian#define	VAR_MODE	23
11238174Sbrian#define	VAR_CALLBACK	24
11338174Sbrian#define	VAR_CBCP	25
11438544Sbrian#define	VAR_CHOKED	26
1156059Samurai
11636285Sbrian/* ``accept|deny|disable|enable'' masks */
11736285Sbrian#define NEG_HISMASK (1)
11836285Sbrian#define NEG_MYMASK (2)
11936285Sbrian
12036285Sbrian/* ``accept|deny|disable|enable'' values */
12136285Sbrian#define NEG_ACFCOMP	40
12236285Sbrian#define NEG_CHAP	41
12336285Sbrian#define NEG_DEFLATE	42
12436285Sbrian#define NEG_LQR		43
12536285Sbrian#define NEG_PAP		44
12636285Sbrian#define NEG_PPPDDEFLATE	45
12736285Sbrian#define NEG_PRED1	46
12836285Sbrian#define NEG_PROTOCOMP	47
12936285Sbrian#define NEG_SHORTSEQ	48
13036285Sbrian#define NEG_VJCOMP	49
13136285Sbrian#define NEG_DNS		50
13236285Sbrian
13337373Sbrianconst char Version[] = "2.0";
13440482Sbrianconst char VersionDate[] = "$Date: 1998/09/17 00:45:26 $";
13536285Sbrian
13636285Sbrianstatic int ShowCommand(struct cmdargs const *);
13736285Sbrianstatic int TerminalCommand(struct cmdargs const *);
13836285Sbrianstatic int QuitCommand(struct cmdargs const *);
13936285Sbrianstatic int OpenCommand(struct cmdargs const *);
14036285Sbrianstatic int CloseCommand(struct cmdargs const *);
14136285Sbrianstatic int DownCommand(struct cmdargs const *);
14236285Sbrianstatic int AllowCommand(struct cmdargs const *);
14336285Sbrianstatic int SetCommand(struct cmdargs const *);
14436285Sbrianstatic int LinkCommand(struct cmdargs const *);
14536285Sbrianstatic int AddCommand(struct cmdargs const *);
14636285Sbrianstatic int DeleteCommand(struct cmdargs const *);
14736285Sbrianstatic int NegotiateCommand(struct cmdargs const *);
14836934Sbrianstatic int ClearCommand(struct cmdargs const *);
14931343Sbrian#ifndef NOALIAS
15036285Sbrianstatic int AliasCommand(struct cmdargs const *);
15136285Sbrianstatic int AliasEnable(struct cmdargs const *);
15236285Sbrianstatic int AliasOption(struct cmdargs const *);
15331343Sbrian#endif
1546059Samurai
15536285Sbrianstatic const char *
15636285Sbrianshowcx(struct cmdtab const *cmd)
15736285Sbrian{
15836285Sbrian  if (cmd->lauth & LOCAL_CX)
15936285Sbrian    return "(c)";
16036285Sbrian  else if (cmd->lauth & LOCAL_CX_OPT)
16136285Sbrian    return "(o)";
16236285Sbrian
16336285Sbrian  return "";
16436285Sbrian}
16536285Sbrian
1666059Samuraistatic int
16731343SbrianHelpCommand(struct cmdargs const *arg)
1686059Samurai{
16928679Sbrian  struct cmdtab const *cmd;
17036285Sbrian  int n, cmax, dmax, cols, cxlen;
17136285Sbrian  const char *cx;
1726059Samurai
17336285Sbrian  if (!arg->prompt) {
17436285Sbrian    log_Printf(LogWARN, "help: Cannot help without a prompt\n");
17526516Sbrian    return 0;
17636285Sbrian  }
17726516Sbrian
17836285Sbrian  if (arg->argc > arg->argn) {
17936285Sbrian    for (cmd = arg->cmdtab; cmd->name || cmd->alias; cmd++)
18036285Sbrian      if ((cmd->lauth & arg->prompt->auth) &&
18136285Sbrian          ((cmd->name && !strcasecmp(cmd->name, arg->argv[arg->argn])) ||
18236285Sbrian           (cmd->alias && !strcasecmp(cmd->alias, arg->argv[arg->argn])))) {
18336285Sbrian	prompt_Printf(arg->prompt, "%s %s\n", cmd->syntax, showcx(cmd));
18428679Sbrian	return 0;
1856059Samurai      }
18626516Sbrian    return -1;
1876059Samurai  }
18836285Sbrian
18931372Sbrian  cmax = dmax = 0;
19036285Sbrian  for (cmd = arg->cmdtab; cmd->func; cmd++)
19136285Sbrian    if (cmd->name && (cmd->lauth & arg->prompt->auth)) {
19236285Sbrian      if ((n = strlen(cmd->name) + strlen(showcx(cmd))) > cmax)
19331372Sbrian        cmax = n;
19431372Sbrian      if ((n = strlen(cmd->helpmes)) > dmax)
19531372Sbrian        dmax = n;
19631372Sbrian    }
19731372Sbrian
19831372Sbrian  cols = 80 / (dmax + cmax + 3);
1996059Samurai  n = 0;
20036285Sbrian  prompt_Printf(arg->prompt, "(o) = Optional context,"
20136285Sbrian                " (c) = Context required\n");
20236285Sbrian  for (cmd = arg->cmdtab; cmd->func; cmd++)
20336285Sbrian    if (cmd->name && (cmd->lauth & arg->prompt->auth)) {
20436285Sbrian      cx = showcx(cmd);
20536285Sbrian      cxlen = cmax - strlen(cmd->name);
20640482Sbrian      if (n % cols != 0)
20740482Sbrian        prompt_Printf(arg->prompt, " ");
20840482Sbrian      prompt_Printf(arg->prompt, "%s%-*.*s: %-*.*s",
20936285Sbrian              cmd->name, cxlen, cxlen, cx, dmax, dmax, cmd->helpmes);
21031372Sbrian      if (++n % cols == 0)
21136285Sbrian        prompt_Printf(arg->prompt, "\n");
2126059Samurai    }
21331372Sbrian  if (n % cols != 0)
21436285Sbrian    prompt_Printf(arg->prompt, "\n");
21526516Sbrian
21626516Sbrian  return 0;
2176059Samurai}
2186059Samurai
21936285Sbrianstatic int
22036285SbrianCloneCommand(struct cmdargs const *arg)
2216059Samurai{
22236285Sbrian  char namelist[LINE_LEN];
22336285Sbrian  char *name;
22436285Sbrian  int f;
2256059Samurai
22636285Sbrian  if (arg->argc == arg->argn)
22736285Sbrian    return -1;
22836285Sbrian
22936285Sbrian  namelist[sizeof namelist - 1] = '\0';
23036285Sbrian  for (f = arg->argn; f < arg->argc; f++) {
23136285Sbrian    strncpy(namelist, arg->argv[f], sizeof namelist - 1);
23236285Sbrian    for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
23336285Sbrian      bundle_DatalinkClone(arg->bundle, arg->cx, name);
2346059Samurai  }
23536285Sbrian
23636285Sbrian  return 0;
2376059Samurai}
2386059Samurai
2396059Samuraistatic int
24036285SbrianRemoveCommand(struct cmdargs const *arg)
2416059Samurai{
24236285Sbrian  if (arg->argc != arg->argn)
24336285Sbrian    return -1;
24411336Samurai
24536285Sbrian  if (arg->cx->state != DATALINK_CLOSED) {
24636285Sbrian    log_Printf(LogWARN, "remove: Cannot delete links that aren't closed\n");
24736285Sbrian    return 2;
2486059Samurai  }
24926516Sbrian
25036285Sbrian  bundle_DatalinkRemove(arg->bundle, arg->cx);
25136285Sbrian  return 0;
25236285Sbrian}
25332711Sbrian
25436285Sbrianstatic int
25536285SbrianRenameCommand(struct cmdargs const *arg)
25636285Sbrian{
25736285Sbrian  if (arg->argc != arg->argn + 1)
25836285Sbrian    return -1;
25931121Sbrian
26036285Sbrian  if (bundle_RenameDatalink(arg->bundle, arg->cx, arg->argv[arg->argn]))
26136285Sbrian    return 0;
26236285Sbrian
26336285Sbrian  log_Printf(LogWARN, "%s -> %s: target name already exists\n",
26436285Sbrian             arg->cx->name, arg->argv[arg->argn]);
26536285Sbrian  return 1;
26636285Sbrian}
26736285Sbrian
26836285Sbrianint
26936285SbrianLoadCommand(struct cmdargs const *arg)
27036285Sbrian{
27136285Sbrian  const char *name;
27236285Sbrian
27336285Sbrian  if (arg->argc > arg->argn)
27436285Sbrian    name = arg->argv[arg->argn];
27536285Sbrian  else
27636285Sbrian    name = "default";
27736285Sbrian
27836928Sbrian  if (!system_IsValid(name, arg->prompt, arg->bundle->phys_type.all)) {
27937019Sbrian    log_Printf(LogWARN, "%s: Label not allowed\n", name);
28036285Sbrian    return 1;
28136285Sbrian  } else {
28236285Sbrian    /*
28336285Sbrian     * Set the label before & after so that `set enddisc' works and
28436285Sbrian     * we handle nested `load' commands.
28536285Sbrian     */
28636285Sbrian    bundle_SetLabel(arg->bundle, arg->argc > arg->argn ? name : NULL);
28737008Sbrian    if (system_Select(arg->bundle, name, CONFFILE, arg->prompt, arg->cx) < 0) {
28836285Sbrian      bundle_SetLabel(arg->bundle, NULL);
28936285Sbrian      log_Printf(LogWARN, "%s: label not found.\n", name);
29036285Sbrian      return -1;
29132403Sbrian    }
29236285Sbrian    bundle_SetLabel(arg->bundle, arg->argc > arg->argn ? name : NULL);
29336285Sbrian  }
29426516Sbrian  return 0;
2956059Samurai}
2966059Samurai
29736285Sbrianint
29836285SbrianSaveCommand(struct cmdargs const *arg)
29936285Sbrian{
30036285Sbrian  log_Printf(LogWARN, "save command is not implemented (yet).\n");
30136285Sbrian  return 1;
30236285Sbrian}
30336285Sbrian
30410528Samuraistatic int
30536285SbrianDialCommand(struct cmdargs const *arg)
30628536Sbrian{
30736285Sbrian  int res;
30836285Sbrian
30936465Sbrian  if ((arg->cx && !(arg->cx->physical->type & (PHYS_INTERACTIVE|PHYS_AUTO)))
31036465Sbrian      || (!arg->cx &&
31136928Sbrian          (arg->bundle->phys_type.all & ~(PHYS_INTERACTIVE|PHYS_AUTO)))) {
31236285Sbrian    log_Printf(LogWARN, "Manual dial is only available for auto and"
31336285Sbrian              " interactive links\n");
31436285Sbrian    return 1;
31534536Sbrian  }
31636285Sbrian
31736285Sbrian  if (arg->argc > arg->argn && (res = LoadCommand(arg)) != 0)
31836285Sbrian    return res;
31936285Sbrian
32037993Sbrian  bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1);
32136285Sbrian
32236285Sbrian  return 0;
32328536Sbrian}
32428536Sbrian
32538628Sbrian#define isinword(ch) (isalnum(ch) || (ch) == '_')
32638628Sbrian
32738628Sbrianstatic char *
32838628Sbrianstrstrword(char *big, const char *little)
32938628Sbrian{
33038628Sbrian  /* Get the first occurance of the word ``little'' in ``big'' */
33138628Sbrian  char *pos;
33238628Sbrian  int len;
33338628Sbrian
33438628Sbrian  pos = big;
33538628Sbrian  len = strlen(little);
33638628Sbrian
33738628Sbrian  while ((pos = strstr(pos, little)) != NULL)
33838628Sbrian    if ((pos == big || !isinword(pos[-1])) && !isinword(pos[len]))
33938628Sbrian      break;
34038628Sbrian    else
34138628Sbrian      pos++;
34238628Sbrian
34338628Sbrian  return pos;
34438628Sbrian}
34538628Sbrian
34638628Sbrianstatic char *
34738628Sbriansubst(char *tgt, const char *oldstr, const char *newstr)
34838628Sbrian{
34938628Sbrian  /* tgt is a malloc()d area... realloc() as necessary */
35038628Sbrian  char *word, *ntgt;
35138628Sbrian  int ltgt, loldstr, lnewstr, pos;
35238628Sbrian
35338628Sbrian  if ((word = strstrword(tgt, oldstr)) == NULL)
35438628Sbrian    return tgt;
35538628Sbrian
35638628Sbrian  ltgt = strlen(tgt) + 1;
35738628Sbrian  loldstr = strlen(oldstr);
35838628Sbrian  lnewstr = strlen(newstr);
35938628Sbrian  do {
36038628Sbrian    pos = word - tgt;
36138628Sbrian    if (loldstr > lnewstr)
36238628Sbrian      bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr);
36338628Sbrian    if (loldstr != lnewstr) {
36438628Sbrian      ntgt = realloc(tgt, ltgt += lnewstr - loldstr);
36538628Sbrian      if (ntgt == NULL)
36638628Sbrian        break;			/* Oh wonderful ! */
36738628Sbrian      word = ntgt + pos;
36838628Sbrian      tgt = ntgt;
36938628Sbrian    }
37038628Sbrian    if (lnewstr > loldstr)
37138628Sbrian      bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr);
37238628Sbrian    bcopy(newstr, word, lnewstr);
37338628Sbrian  } while ((word = strstrword(word, oldstr)));
37438628Sbrian
37538628Sbrian  return tgt;
37638628Sbrian}
37738628Sbrian
37838628Sbrianstatic void
37938628Sbrianexpand(char **nargv, int argc, char const *const *oargv, struct bundle *bundle)
38038628Sbrian{
38138628Sbrian  int arg;
38238628Sbrian
38338628Sbrian  nargv[0] = strdup(oargv[0]);
38438628Sbrian  for (arg = 1; arg < argc; arg++) {
38538629Sbrian    nargv[arg] = strdup(oargv[arg]);
38638629Sbrian    nargv[arg] = subst(nargv[arg], "HISADDR",
38738628Sbrian                       inet_ntoa(bundle->ncp.ipcp.peer_ip));
38838629Sbrian    nargv[arg] = subst(nargv[arg], "AUTHNAME", bundle->cfg.auth.name);
38938628Sbrian    nargv[arg] = subst(nargv[arg], "INTERFACE", bundle->ifp.Name);
39038628Sbrian    nargv[arg] = subst(nargv[arg], "MYADDR", inet_ntoa(bundle->ncp.ipcp.my_ip));
39138629Sbrian    nargv[arg] = subst(nargv[arg], "USER", bundle->ncp.mp.peer.authname);
39238629Sbrian    nargv[arg] = subst(nargv[arg], "PEER_ENDDISC",
39338629Sbrian                       mp_Enddisc(bundle->ncp.mp.peer.enddisc.class,
39438629Sbrian                                  bundle->ncp.mp.peer.enddisc.address,
39538629Sbrian                                  bundle->ncp.mp.peer.enddisc.len));
39638629Sbrian    nargv[arg] = subst(nargv[arg], "ENDDISC",
39738629Sbrian                       mp_Enddisc(bundle->ncp.mp.cfg.enddisc.class,
39838629Sbrian                                  bundle->ncp.mp.cfg.enddisc.address,
39938629Sbrian                                  bundle->ncp.mp.cfg.enddisc.len));
40038629Sbrian    nargv[arg] = subst(nargv[arg], "LABEL", bundle_GetLabel(bundle));
40138628Sbrian  }
40238628Sbrian  nargv[arg] = NULL;
40338628Sbrian}
40438628Sbrian
40528536Sbrianstatic int
40631343SbrianShellCommand(struct cmdargs const *arg, int bg)
40710528Samurai{
40810528Samurai  const char *shell;
40910528Samurai  pid_t shpid;
41020813Sjkh
41118856Ssos#ifdef SHELL_ONLY_INTERACTIVELY
41226911Sbrian  /* we're only allowed to shell when we run ppp interactively */
41336285Sbrian  if (arg->prompt && arg->prompt->owner) {
41436285Sbrian    log_Printf(LogWARN, "Can't start a shell from a network connection\n");
41526516Sbrian    return 1;
41610528Samurai  }
41726911Sbrian#endif
41828679Sbrian
41936285Sbrian  if (arg->argc == arg->argn) {
42036285Sbrian    if (!arg->prompt) {
42136285Sbrian      log_Printf(LogWARN, "Can't start an interactive shell from"
42236285Sbrian                " a config file\n");
42328381Sbrian      return 1;
42436285Sbrian    } else if (arg->prompt->owner) {
42536285Sbrian      log_Printf(LogWARN, "Can't start an interactive shell from"
42636285Sbrian                " a socket connection\n");
42736285Sbrian      return 1;
42828381Sbrian    } else if (bg) {
42936285Sbrian      log_Printf(LogWARN, "Can only start an interactive shell in"
43028679Sbrian		" the foreground mode\n");
43128381Sbrian      return 1;
43228381Sbrian    }
43334536Sbrian  }
43434536Sbrian
43528679Sbrian  if ((shpid = fork()) == 0) {
43636285Sbrian    int i, fd;
43718531Sbde
43836285Sbrian    if ((shell = getenv("SHELL")) == 0)
43936285Sbrian      shell = _PATH_BSHELL;
44032017Sbrian
44136285Sbrian    timer_TermService();
44236285Sbrian
44336285Sbrian    if (arg->prompt)
44436285Sbrian      fd = arg->prompt->fd_out;
44536285Sbrian    else if ((fd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
44636285Sbrian      log_Printf(LogALERT, "Failed to open %s: %s\n",
44736285Sbrian                _PATH_DEVNULL, strerror(errno));
44828679Sbrian      exit(1);
44928679Sbrian    }
45028679Sbrian    for (i = 0; i < 3; i++)
45128679Sbrian      dup2(fd, i);
45226516Sbrian
45336285Sbrian    fcntl(3, F_SETFD, 1);	/* Set close-on-exec flag */
45426516Sbrian
45531061Sbrian    setuid(geteuid());
45636285Sbrian    if (arg->argc > arg->argn) {
45728679Sbrian      /* substitute pseudo args */
45838628Sbrian      char *argv[MAXARGS];
45938628Sbrian      int argc = arg->argc - arg->argn;
46038628Sbrian
46138628Sbrian      if (argc >= sizeof argv / sizeof argv[0]) {
46238628Sbrian        argc = sizeof argv / sizeof argv[0] - 1;
46338628Sbrian        log_Printf(LogWARN, "Truncating shell command to %d args\n", argc);
46431343Sbrian      }
46538628Sbrian      expand(argv, argc, arg->argv + arg->argn, arg->bundle);
46628679Sbrian      if (bg) {
46728679Sbrian	pid_t p;
46810528Samurai
46928679Sbrian	p = getpid();
47028679Sbrian	if (daemon(1, 1) == -1) {
47136832Sbrian	  log_Printf(LogERROR, "%d: daemon: %s\n", (int)p, strerror(errno));
47228679Sbrian	  exit(1);
47328679Sbrian	}
47436285Sbrian      } else if (arg->prompt)
47536285Sbrian        printf("ppp: Pausing until %s finishes\n", arg->argv[arg->argn]);
47631343Sbrian      execvp(argv[0], argv);
47730316Sbrian    } else {
47836285Sbrian      if (arg->prompt)
47932017Sbrian        printf("ppp: Pausing until %s finishes\n", shell);
48036285Sbrian      prompt_TtyOldMode(arg->prompt);
48131343Sbrian      execl(shell, shell, NULL);
48230316Sbrian    }
48320813Sjkh
48436285Sbrian    log_Printf(LogWARN, "exec() of %s failed\n",
48536285Sbrian              arg->argc > arg->argn ? arg->argv[arg->argn] : shell);
48628679Sbrian    exit(255);
48710528Samurai  }
48836285Sbrian
48936285Sbrian  if (shpid == (pid_t) - 1)
49036285Sbrian    log_Printf(LogERROR, "Fork failed: %s\n", strerror(errno));
49136285Sbrian  else {
49210528Samurai    int status;
49331343Sbrian    waitpid(shpid, &status, 0);
49410528Samurai  }
49520813Sjkh
49636285Sbrian  if (arg->prompt && !arg->prompt->owner)
49736285Sbrian    prompt_TtyCommandMode(arg->prompt);
49820813Sjkh
49936285Sbrian  return 0;
50010528Samurai}
50110528Samurai
50231343Sbrianstatic int
50331343SbrianBgShellCommand(struct cmdargs const *arg)
50431343Sbrian{
50536285Sbrian  if (arg->argc == arg->argn)
50631343Sbrian    return -1;
50731343Sbrian  return ShellCommand(arg, 1);
50831343Sbrian}
50931343Sbrian
51031343Sbrianstatic int
51131343SbrianFgShellCommand(struct cmdargs const *arg)
51231343Sbrian{
51331343Sbrian  return ShellCommand(arg, 0);
51431343Sbrian}
51531343Sbrian
51630715Sbrianstatic struct cmdtab const Commands[] = {
51736285Sbrian  {"accept", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
51828679Sbrian  "accept option request", "accept option .."},
51928679Sbrian  {"add", NULL, AddCommand, LOCAL_AUTH,
52032109Sbrian  "add route", "add dest mask gateway", NULL},
52136285Sbrian  {NULL, "add!", AddCommand, LOCAL_AUTH,
52232109Sbrian  "add or change route", "add! dest mask gateway", (void *)1},
52336285Sbrian#ifndef NOALIAS
52436285Sbrian  {"alias", NULL, AliasCommand, LOCAL_AUTH,
52536285Sbrian  "alias control", "alias option [yes|no]"},
52636285Sbrian#endif
52731121Sbrian  {"allow", "auth", AllowCommand, LOCAL_AUTH,
52831121Sbrian  "Allow ppp access", "allow users|modes ...."},
52928679Sbrian  {"bg", "!bg", BgShellCommand, LOCAL_AUTH,
53031372Sbrian  "Run a background command", "[!]bg command"},
53136934Sbrian  {"clear", NULL, ClearCommand, LOCAL_AUTH | LOCAL_CX_OPT,
53236934Sbrian  "Clear throughput statistics", "clear ipcp|modem [current|overall|peak]..."},
53336285Sbrian  {"clone", NULL, CloneCommand, LOCAL_AUTH | LOCAL_CX,
53436285Sbrian  "Clone a link", "clone newname..."},
53536285Sbrian  {"close", NULL, CloseCommand, LOCAL_AUTH | LOCAL_CX_OPT,
53636285Sbrian  "Close an FSM", "close [lcp|ccp]"},
53728679Sbrian  {"delete", NULL, DeleteCommand, LOCAL_AUTH,
53832109Sbrian  "delete route", "delete dest", NULL},
53936285Sbrian  {NULL, "delete!", DeleteCommand, LOCAL_AUTH,
54032109Sbrian  "delete a route if it exists", "delete! dest", (void *)1},
54136285Sbrian  {"deny", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
54228679Sbrian  "Deny option request", "deny option .."},
54336285Sbrian  {"dial", "call", DialCommand, LOCAL_AUTH | LOCAL_CX_OPT,
54437955Sbrian  "Dial and login", "dial|call [remote]", NULL},
54536285Sbrian  {"disable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
54628679Sbrian  "Disable option", "disable option .."},
54736285Sbrian  {"down", NULL, DownCommand, LOCAL_AUTH | LOCAL_CX_OPT,
54836285Sbrian  "Generate a down event", "down"},
54936285Sbrian  {"enable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
55028679Sbrian  "Enable option", "enable option .."},
55136285Sbrian  {"link", "datalink", LinkCommand, LOCAL_AUTH,
55236285Sbrian  "Link specific commands", "link name command ..."},
55337008Sbrian  {"load", NULL, LoadCommand, LOCAL_AUTH | LOCAL_CX_OPT,
55428679Sbrian  "Load settings", "load [remote]"},
55536285Sbrian  {"open", NULL, OpenCommand, LOCAL_AUTH | LOCAL_CX_OPT,
55637955Sbrian  "Open an FSM", "open! [lcp|ccp|ipcp]", (void *)1},
55736285Sbrian  {"passwd", NULL, PasswdCommand, LOCAL_NO_AUTH,
55836285Sbrian  "Password for manipulation", "passwd LocalPassword"},
55936285Sbrian  {"quit", "bye", QuitCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
56036285Sbrian  "Quit PPP program", "quit|bye [all]"},
56136285Sbrian  {"remove", "rm", RemoveCommand, LOCAL_AUTH | LOCAL_CX,
56236285Sbrian  "Remove a link", "remove"},
56336285Sbrian  {"rename", "mv", RenameCommand, LOCAL_AUTH | LOCAL_CX,
56436285Sbrian  "Rename a link", "rename name"},
56528679Sbrian  {"save", NULL, SaveCommand, LOCAL_AUTH,
56628679Sbrian  "Save settings", "save"},
56736285Sbrian  {"set", "setup", SetCommand, LOCAL_AUTH | LOCAL_CX_OPT,
56828679Sbrian  "Set parameters", "set[up] var value"},
56928679Sbrian  {"shell", "!", FgShellCommand, LOCAL_AUTH,
57028679Sbrian  "Run a subshell", "shell|! [sh command]"},
57136285Sbrian  {"show", NULL, ShowCommand, LOCAL_AUTH | LOCAL_CX_OPT,
57231372Sbrian  "Show status and stats", "show var"},
57336285Sbrian  {"term", NULL, TerminalCommand, LOCAL_AUTH | LOCAL_CX,
57431372Sbrian  "Enter terminal mode", "term"},
57528679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
57631343Sbrian  "Display this message", "help|? [command]", Commands},
57728679Sbrian  {NULL, NULL, NULL},
5786059Samurai};
5796059Samurai
58028536Sbrianstatic int
58131343SbrianShowEscape(struct cmdargs const *arg)
5826059Samurai{
58336285Sbrian  if (arg->cx->physical->async.cfg.EscMap[32]) {
58436285Sbrian    int code, bit;
58536285Sbrian    const char *sep = "";
5866059Samurai
58726516Sbrian    for (code = 0; code < 32; code++)
58836285Sbrian      if (arg->cx->physical->async.cfg.EscMap[code])
58928679Sbrian	for (bit = 0; bit < 8; bit++)
59036285Sbrian	  if (arg->cx->physical->async.cfg.EscMap[code] & (1 << bit)) {
59136285Sbrian	    prompt_Printf(arg->prompt, "%s0x%02x", sep, (code << 3) + bit);
59236285Sbrian            sep = ", ";
59336285Sbrian          }
59436285Sbrian    prompt_Printf(arg->prompt, "\n");
5956059Samurai  }
59631077Sbrian  return 0;
5976059Samurai}
5986059Samurai
59928679Sbrianstatic int
60036285SbrianShowTimerList(struct cmdargs const *arg)
6016059Samurai{
60236285Sbrian  timer_Show(0, arg->prompt);
60331077Sbrian  return 0;
6046059Samurai}
6056059Samurai
60628679Sbrianstatic int
60731343SbrianShowStopped(struct cmdargs const *arg)
60828327Sbrian{
60936285Sbrian  prompt_Printf(arg->prompt, " Stopped Timer:  LCP: ");
61036285Sbrian  if (!arg->cx->physical->link.lcp.fsm.StoppedTimer.load)
61136285Sbrian    prompt_Printf(arg->prompt, "Disabled");
61228327Sbrian  else
61336285Sbrian    prompt_Printf(arg->prompt, "%ld secs",
61436285Sbrian                  arg->cx->physical->link.lcp.fsm.StoppedTimer.load / SECTICKS);
61528461Sbrian
61636285Sbrian  prompt_Printf(arg->prompt, ", CCP: ");
61736285Sbrian  if (!arg->cx->physical->link.ccp.fsm.StoppedTimer.load)
61836285Sbrian    prompt_Printf(arg->prompt, "Disabled");
61928461Sbrian  else
62036285Sbrian    prompt_Printf(arg->prompt, "%ld secs",
62136285Sbrian                  arg->cx->physical->link.ccp.fsm.StoppedTimer.load / SECTICKS);
62228461Sbrian
62336285Sbrian  prompt_Printf(arg->prompt, "\n");
62428461Sbrian
62531077Sbrian  return 0;
62628327Sbrian}
62728327Sbrian
62828679Sbrianstatic int
62931343SbrianShowVersion(struct cmdargs const *arg)
6306059Samurai{
63136285Sbrian  prompt_Printf(arg->prompt, "PPP Version %s - %s\n", Version, VersionDate);
63231077Sbrian  return 0;
6336059Samurai}
6346059Samurai
63528679Sbrianstatic int
63636285SbrianShowProtocolStats(struct cmdargs const *arg)
63726326Sbrian{
63836285Sbrian  struct link *l = command_ChooseLink(arg);
63926326Sbrian
64036285Sbrian  prompt_Printf(arg->prompt, "%s:\n", l->name);
64136285Sbrian  link_ReportProtocolStatus(l, arg->prompt);
64231077Sbrian  return 0;
64326326Sbrian}
64426326Sbrian
64530715Sbrianstatic struct cmdtab const ShowCommands[] = {
64636285Sbrian  {"bundle", NULL, bundle_ShowStatus, LOCAL_AUTH,
64736285Sbrian  "bundle details", "show bundle"},
64836285Sbrian  {"ccp", NULL, ccp_ReportStatus, LOCAL_AUTH | LOCAL_CX_OPT,
64936285Sbrian  "CCP status", "show cpp"},
65036285Sbrian  {"compress", NULL, sl_Show, LOCAL_AUTH,
65136285Sbrian  "VJ compression stats", "show compress"},
65236285Sbrian  {"escape", NULL, ShowEscape, LOCAL_AUTH | LOCAL_CX,
65336285Sbrian  "escape characters", "show escape"},
65436285Sbrian  {"filter", NULL, filter_Show, LOCAL_AUTH,
65536285Sbrian  "packet filters", "show filter [in|out|dial|alive]"},
65636285Sbrian  {"hdlc", NULL, hdlc_ReportStatus, LOCAL_AUTH | LOCAL_CX,
65736285Sbrian  "HDLC errors", "show hdlc"},
65836285Sbrian  {"ipcp", NULL, ipcp_Show, LOCAL_AUTH,
65936285Sbrian  "IPCP status", "show ipcp"},
66036285Sbrian  {"lcp", NULL, lcp_ReportStatus, LOCAL_AUTH | LOCAL_CX,
66136285Sbrian  "LCP status", "show lcp"},
66236285Sbrian  {"link", "datalink", datalink_Show, LOCAL_AUTH | LOCAL_CX,
66336285Sbrian  "(high-level) link info", "show link"},
66436285Sbrian  {"links", NULL, bundle_ShowLinks, LOCAL_AUTH,
66536285Sbrian  "available link names", "show links"},
66636285Sbrian  {"log", NULL, log_ShowLevel, LOCAL_AUTH,
66736285Sbrian  "log levels", "show log"},
66836285Sbrian  {"mem", NULL, mbuf_Show, LOCAL_AUTH,
66936285Sbrian  "mbuf allocations", "show mem"},
67036285Sbrian  {"modem", NULL, modem_ShowStatus, LOCAL_AUTH | LOCAL_CX,
67136285Sbrian  "(low-level) link info", "show modem"},
67236285Sbrian  {"mp", "multilink", mp_ShowStatus, LOCAL_AUTH,
67336285Sbrian  "multilink setup", "show mp"},
67436285Sbrian  {"proto", NULL, ShowProtocolStats, LOCAL_AUTH | LOCAL_CX_OPT,
67536285Sbrian  "protocol summary", "show proto"},
67636285Sbrian  {"route", NULL, route_Show, LOCAL_AUTH,
67736285Sbrian  "routing table", "show route"},
67836285Sbrian  {"stopped", NULL, ShowStopped, LOCAL_AUTH | LOCAL_CX,
67936285Sbrian  "STOPPED timeout", "show stopped"},
68036285Sbrian  {"timers", NULL, ShowTimerList, LOCAL_AUTH,
68136285Sbrian  "alarm timers", "show timers"},
68228679Sbrian  {"version", NULL, ShowVersion, LOCAL_NO_AUTH | LOCAL_AUTH,
68336285Sbrian  "version string", "show version"},
68436285Sbrian  {"who", NULL, log_ShowWho, LOCAL_AUTH,
68536285Sbrian  "client list", "show who"},
68628679Sbrian  {"help", "?", HelpCommand, LOCAL_NO_AUTH | LOCAL_AUTH,
68731343Sbrian  "Display this message", "show help|? [command]", ShowCommands},
68828679Sbrian  {NULL, NULL, NULL},
6896059Samurai};
6906059Samurai
69130715Sbrianstatic struct cmdtab const *
69231343SbrianFindCommand(struct cmdtab const *cmds, const char *str, int *pmatch)
6936059Samurai{
69426516Sbrian  int nmatch;
69526516Sbrian  int len;
69628679Sbrian  struct cmdtab const *found;
6976059Samurai
69826516Sbrian  found = NULL;
69926516Sbrian  len = strlen(str);
70026516Sbrian  nmatch = 0;
7016059Samurai  while (cmds->func) {
70225566Sbrian    if (cmds->name && strncasecmp(str, cmds->name, len) == 0) {
70326516Sbrian      if (cmds->name[len] == '\0') {
70428679Sbrian	*pmatch = 1;
70528679Sbrian	return cmds;
70626516Sbrian      }
7076059Samurai      nmatch++;
7086059Samurai      found = cmds;
70928679Sbrian    } else if (cmds->alias && strncasecmp(str, cmds->alias, len) == 0) {
71026516Sbrian      if (cmds->alias[len] == '\0') {
71128679Sbrian	*pmatch = 1;
71228679Sbrian	return cmds;
71326516Sbrian      }
7146059Samurai      nmatch++;
7156059Samurai      found = cmds;
7166059Samurai    }
7176059Samurai    cmds++;
7186059Samurai  }
7196059Samurai  *pmatch = nmatch;
72026516Sbrian  return found;
7216059Samurai}
7226059Samurai
72336285Sbrianstatic const char *
72436285SbrianmkPrefix(int argc, char const *const *argv, char *tgt, int sz)
72536285Sbrian{
72636285Sbrian  int f, tlen, len;
72736285Sbrian
72836285Sbrian  tlen = 0;
72936285Sbrian  for (f = 0; f < argc && tlen < sz - 2; f++) {
73036285Sbrian    if (f)
73136285Sbrian      tgt[tlen++] = ' ';
73236285Sbrian    len = strlen(argv[f]);
73336285Sbrian    if (len > sz - tlen - 1)
73436285Sbrian      len = sz - tlen - 1;
73536285Sbrian    strncpy(tgt+tlen, argv[f], len);
73636285Sbrian    tlen += len;
73736285Sbrian  }
73836285Sbrian  tgt[tlen] = '\0';
73936285Sbrian  return tgt;
74036285Sbrian}
74136285Sbrian
74230715Sbrianstatic int
74336285SbrianFindExec(struct bundle *bundle, struct cmdtab const *cmds, int argc, int argn,
74436285Sbrian         char const *const *argv, struct prompt *prompt, struct datalink *cx)
7456059Samurai{
74628679Sbrian  struct cmdtab const *cmd;
7476059Samurai  int val = 1;
7486059Samurai  int nmatch;
74931343Sbrian  struct cmdargs arg;
75036285Sbrian  char prefix[100];
7516059Samurai
75236285Sbrian  cmd = FindCommand(cmds, argv[argn], &nmatch);
7536059Samurai  if (nmatch > 1)
75436285Sbrian    log_Printf(LogWARN, "%s: Ambiguous command\n",
75536285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix));
75636285Sbrian  else if (cmd && (!prompt || (cmd->lauth & prompt->auth))) {
75736285Sbrian    if ((cmd->lauth & LOCAL_CX) && !cx)
75836285Sbrian      /* We've got no context, but we require it */
75936285Sbrian      cx = bundle2datalink(bundle, NULL);
76036285Sbrian
76136285Sbrian    if ((cmd->lauth & LOCAL_CX) && !cx)
76236285Sbrian      log_Printf(LogWARN, "%s: No context (use the `link' command)\n",
76336285Sbrian                mkPrefix(argn+1, argv, prefix, sizeof prefix));
76436285Sbrian    else {
76536285Sbrian      if (cx && !(cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
76636285Sbrian        log_Printf(LogWARN, "%s: Redundant context (%s) ignored\n",
76736285Sbrian                  mkPrefix(argn+1, argv, prefix, sizeof prefix), cx->name);
76836285Sbrian        cx = NULL;
76936285Sbrian      }
77036285Sbrian      arg.cmdtab = cmds;
77136285Sbrian      arg.cmd = cmd;
77236285Sbrian      arg.argc = argc;
77336285Sbrian      arg.argn = argn+1;
77436285Sbrian      arg.argv = argv;
77536285Sbrian      arg.bundle = bundle;
77636285Sbrian      arg.cx = cx;
77736285Sbrian      arg.prompt = prompt;
77836285Sbrian      val = (*cmd->func) (&arg);
77936285Sbrian    }
78031343Sbrian  } else
78136285Sbrian    log_Printf(LogWARN, "%s: Invalid command\n",
78236285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix));
78326516Sbrian
78426516Sbrian  if (val == -1)
78536285Sbrian    log_Printf(LogWARN, "Usage: %s\n", cmd->syntax);
78628679Sbrian  else if (val)
78736285Sbrian    log_Printf(LogWARN, "%s: Failed %d\n",
78836285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix), val);
78926516Sbrian
79026516Sbrian  return val;
7916059Samurai}
7926059Samurai
79337009Sbrianint
79437009Sbriancommand_Interpret(char *buff, int nb, char *argv[MAXARGS])
7956059Samurai{
7966059Samurai  char *cp;
7976059Samurai
7986059Samurai  if (nb > 0) {
7996059Samurai    cp = buff + strcspn(buff, "\r\n");
8006059Samurai    if (cp)
8016059Samurai      *cp = '\0';
80237009Sbrian    return MakeArgs(buff, argv, MAXARGS);
80337009Sbrian  }
80437009Sbrian  return 0;
80531121Sbrian}
8066059Samurai
80731822Sbrianstatic int
80831822Sbrianarghidden(int argc, char const *const *argv, int n)
80931822Sbrian{
81031822Sbrian  /* Is arg n of the given command to be hidden from the log ? */
81131828Sbrian
81231828Sbrian  /* set authkey xxxxx */
81331828Sbrian  /* set key xxxxx */
81431822Sbrian  if (n == 2 && !strncasecmp(argv[0], "se", 2) &&
81531822Sbrian      (!strncasecmp(argv[1], "authk", 5) || !strncasecmp(argv[1], "ke", 2)))
81631822Sbrian    return 1;
81731822Sbrian
81831828Sbrian  /* passwd xxxxx */
81931828Sbrian  if (n == 1 && !strncasecmp(argv[0], "p", 1))
82031828Sbrian    return 1;
82131828Sbrian
82236285Sbrian  /* set server port xxxxx .... */
82336285Sbrian  if (n == 3 && !strncasecmp(argv[0], "se", 2) &&
82436285Sbrian      !strncasecmp(argv[1], "se", 2))
82536285Sbrian    return 1;
82636285Sbrian
82731822Sbrian  return 0;
82831822Sbrian}
82931822Sbrian
83031121Sbrianvoid
83136285Sbriancommand_Run(struct bundle *bundle, int argc, char const *const *argv,
83237008Sbrian           struct prompt *prompt, const char *label, struct datalink *cx)
83331121Sbrian{
83431156Sbrian  if (argc > 0) {
83536285Sbrian    if (log_IsKept(LogCOMMAND)) {
83631156Sbrian      static char buf[LINE_LEN];
83731156Sbrian      int f, n;
83831156Sbrian
83931156Sbrian      *buf = '\0';
84031156Sbrian      if (label) {
84131962Sbrian        strncpy(buf, label, sizeof buf - 3);
84231962Sbrian        buf[sizeof buf - 3] = '\0';
84331156Sbrian        strcat(buf, ": ");
84431156Sbrian      }
84531156Sbrian      n = strlen(buf);
84631156Sbrian      for (f = 0; f < argc; f++) {
84731962Sbrian        if (n < sizeof buf - 1 && f)
84831156Sbrian          buf[n++] = ' ';
84931822Sbrian        if (arghidden(argc, argv, f))
85036285Sbrian          strncpy(buf+n, "********", sizeof buf - n - 1);
85131822Sbrian        else
85231962Sbrian          strncpy(buf+n, argv[f], sizeof buf - n - 1);
85331156Sbrian        n += strlen(buf+n);
85431156Sbrian      }
85536285Sbrian      log_Printf(LogCOMMAND, "%s\n", buf);
85631156Sbrian    }
85737008Sbrian    FindExec(bundle, Commands, argc, 0, argv, prompt, cx);
85831156Sbrian  }
8596059Samurai}
8606059Samurai
86131121Sbrianvoid
86236285Sbriancommand_Decode(struct bundle *bundle, char *buff, int nb, struct prompt *prompt,
86336285Sbrian              const char *label)
86431121Sbrian{
86531121Sbrian  int argc;
86637009Sbrian  char *argv[MAXARGS];
86731121Sbrian
86837009Sbrian  argc = command_Interpret(buff, nb, argv);
86937008Sbrian  command_Run(bundle, argc, (char const *const *)argv, prompt, label, NULL);
87031121Sbrian}
87131121Sbrian
8726059Samuraistatic int
87331343SbrianShowCommand(struct cmdargs const *arg)
8746059Samurai{
87536285Sbrian  if (!arg->prompt)
87636285Sbrian    log_Printf(LogWARN, "show: Cannot show without a prompt\n");
87736285Sbrian  else if (arg->argc > arg->argn)
87836285Sbrian    FindExec(arg->bundle, ShowCommands, arg->argc, arg->argn, arg->argv,
87936285Sbrian             arg->prompt, arg->cx);
8806059Samurai  else
88136285Sbrian    prompt_Printf(arg->prompt, "Use ``show ?'' to get a list.\n");
88226516Sbrian
88326516Sbrian  return 0;
8846059Samurai}
8856059Samurai
8866059Samuraistatic int
88731343SbrianTerminalCommand(struct cmdargs const *arg)
8886059Samurai{
88936285Sbrian  if (!arg->prompt) {
89036285Sbrian    log_Printf(LogWARN, "term: Need a prompt\n");
89126516Sbrian    return 1;
8926059Samurai  }
89336285Sbrian
89436285Sbrian  if (arg->cx->physical->link.lcp.fsm.state > ST_CLOSED) {
89536285Sbrian    prompt_Printf(arg->prompt, "LCP state is [%s]\n",
89636285Sbrian                  State2Nam(arg->cx->physical->link.lcp.fsm.state));
89736285Sbrian    return 1;
8986059Samurai  }
89936285Sbrian
90036285Sbrian  datalink_Up(arg->cx, 0, 0);
90136285Sbrian  prompt_TtyTermMode(arg->prompt, arg->cx);
90236285Sbrian  return 0;
9036059Samurai}
9046059Samurai
9056059Samuraistatic int
90631343SbrianQuitCommand(struct cmdargs const *arg)
9076059Samurai{
90836285Sbrian  if (!arg->prompt || prompt_IsController(arg->prompt) ||
90936285Sbrian      (arg->argc > arg->argn && !strcasecmp(arg->argv[arg->argn], "all") &&
91036285Sbrian       (arg->prompt->auth & LOCAL_AUTH)))
91136285Sbrian    Cleanup(EX_NORMAL);
91236285Sbrian  if (arg->prompt)
91336285Sbrian    prompt_Destroy(arg->prompt, 1);
91426516Sbrian
91526516Sbrian  return 0;
9166059Samurai}
9176059Samurai
9186059Samuraistatic int
91936285SbrianOpenCommand(struct cmdargs const *arg)
9206059Samurai{
92137160Sbrian  if (arg->argc == arg->argn)
92237993Sbrian    bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1);
92337160Sbrian  else if (arg->argc == arg->argn + 1) {
92437160Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp")) {
92537385Sbrian      struct datalink *cx = arg->cx ?
92637385Sbrian        arg->cx : bundle2datalink(arg->bundle, NULL);
92737385Sbrian      if (cx) {
92837385Sbrian        if (cx->physical->link.lcp.fsm.state == ST_OPENED)
92937385Sbrian          fsm_Reopen(&cx->physical->link.lcp.fsm);
93037160Sbrian        else
93137993Sbrian          bundle_Open(arg->bundle, cx->name, PHYS_ALL, 1);
93237160Sbrian      } else
93337160Sbrian        log_Printf(LogWARN, "open lcp: You must specify a link\n");
93437160Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) {
93537160Sbrian      struct fsm *fp;
9366059Samurai
93737210Sbrian      fp = &command_ChooseLink(arg)->ccp.fsm;
93837160Sbrian      if (fp->link->lcp.fsm.state != ST_OPENED)
93937160Sbrian        log_Printf(LogWARN, "open: LCP must be open before opening CCP\n");
94037160Sbrian      else if (fp->state == ST_OPENED)
94137160Sbrian        fsm_Reopen(fp);
94237160Sbrian      else {
94337160Sbrian        fp->open_mode = 0;	/* Not passive any more */
94437160Sbrian        if (fp->state == ST_STOPPED) {
94537160Sbrian          fsm_Down(fp);
94637160Sbrian          fsm_Up(fp);
94737160Sbrian        } else {
94837160Sbrian          fsm_Up(fp);
94937160Sbrian          fsm_Open(fp);
95037160Sbrian        }
95136285Sbrian      }
95237160Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ipcp")) {
95337160Sbrian      if (arg->cx)
95437160Sbrian        log_Printf(LogWARN, "open ipcp: You need not specify a link\n");
95537160Sbrian      if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED)
95637160Sbrian        fsm_Reopen(&arg->bundle->ncp.ipcp.fsm);
95737160Sbrian      else
95837993Sbrian        bundle_Open(arg->bundle, NULL, PHYS_ALL, 1);
95937160Sbrian    } else
96037160Sbrian      return -1;
96136285Sbrian  } else
96236285Sbrian    return -1;
96336285Sbrian
96426516Sbrian  return 0;
9656059Samurai}
9666059Samurai
96725067Sbrianstatic int
96836285SbrianCloseCommand(struct cmdargs const *arg)
9696059Samurai{
97037007Sbrian  if (arg->argc == arg->argn)
97137007Sbrian    bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_STAYDOWN);
97237007Sbrian  else if (arg->argc == arg->argn + 1) {
97337007Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp"))
97437007Sbrian      bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_LCP);
97537007Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "ccp") ||
97637007Sbrian             !strcasecmp(arg->argv[arg->argn], "ccp!")) {
97737007Sbrian      struct fsm *fp;
9786059Samurai
97937210Sbrian      fp = &command_ChooseLink(arg)->ccp.fsm;
98037007Sbrian      if (fp->state == ST_OPENED) {
98137007Sbrian        fsm_Close(fp);
98237007Sbrian        if (arg->argv[arg->argn][3] == '!')
98337007Sbrian          fp->open_mode = 0;		/* Stay ST_CLOSED */
98437007Sbrian        else
98537007Sbrian          fp->open_mode = OPEN_PASSIVE;	/* Wait for the peer to start */
98637007Sbrian      }
98737007Sbrian    } else
98836285Sbrian      return -1;
98936285Sbrian  } else
99036285Sbrian    return -1;
99136285Sbrian
99236285Sbrian  return 0;
9936059Samurai}
9946059Samurai
99525067Sbrianstatic int
99636285SbrianDownCommand(struct cmdargs const *arg)
99711336Samurai{
99837018Sbrian  if (arg->argc == arg->argn) {
99937018Sbrian      if (arg->cx)
100037018Sbrian        datalink_Down(arg->cx, CLOSE_STAYDOWN);
100137018Sbrian      else
100237018Sbrian        bundle_Down(arg->bundle, CLOSE_STAYDOWN);
100337018Sbrian  } else if (arg->argc == arg->argn + 1) {
100437018Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp")) {
100537018Sbrian      if (arg->cx)
100637018Sbrian        datalink_Down(arg->cx, CLOSE_LCP);
100737018Sbrian      else
100837018Sbrian        bundle_Down(arg->bundle, CLOSE_LCP);
100937018Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) {
101037018Sbrian      struct fsm *fp = arg->cx ? &arg->cx->physical->link.ccp.fsm :
101137018Sbrian                                 &arg->bundle->ncp.mp.link.ccp.fsm;
101237060Sbrian      fsm2initial(fp);
101337018Sbrian    } else
101437018Sbrian      return -1;
101536285Sbrian  } else
101636285Sbrian    return -1;
101736285Sbrian
101836285Sbrian  return 0;
101925067Sbrian}
102025067Sbrian
102125067Sbrianstatic int
102236285SbrianSetModemSpeed(struct cmdargs const *arg)
102325067Sbrian{
102436285Sbrian  long speed;
102536285Sbrian  char *end;
102611336Samurai
102736285Sbrian  if (arg->argc > arg->argn && *arg->argv[arg->argn]) {
102836285Sbrian    if (arg->argc > arg->argn+1) {
102936285Sbrian      log_Printf(LogWARN, "SetModemSpeed: Too many arguments");
103036285Sbrian      return -1;
103111336Samurai    }
103236285Sbrian    if (strcasecmp(arg->argv[arg->argn], "sync") == 0) {
103336285Sbrian      physical_SetSync(arg->cx->physical);
103436285Sbrian      return 0;
103536285Sbrian    }
103636285Sbrian    end = NULL;
103736285Sbrian    speed = strtol(arg->argv[arg->argn], &end, 10);
103836285Sbrian    if (*end) {
103936285Sbrian      log_Printf(LogWARN, "SetModemSpeed: Bad argument \"%s\"",
104036285Sbrian                arg->argv[arg->argn]);
104136285Sbrian      return -1;
104236285Sbrian    }
104336285Sbrian    if (physical_SetSpeed(arg->cx->physical, speed))
104436285Sbrian      return 0;
104536285Sbrian    log_Printf(LogWARN, "%s: Invalid speed\n", arg->argv[arg->argn]);
104636285Sbrian  } else
104736285Sbrian    log_Printf(LogWARN, "SetModemSpeed: No speed specified\n");
104824939Sbrian
104926516Sbrian  return -1;
105011336Samurai}
105111336Samurai
105225067Sbrianstatic int
105331343SbrianSetStoppedTimeout(struct cmdargs const *arg)
105428327Sbrian{
105536285Sbrian  struct link *l = &arg->cx->physical->link;
105636285Sbrian
105736285Sbrian  l->lcp.fsm.StoppedTimer.load = 0;
105836285Sbrian  l->ccp.fsm.StoppedTimer.load = 0;
105936285Sbrian  if (arg->argc <= arg->argn+2) {
106036285Sbrian    if (arg->argc > arg->argn) {
106136285Sbrian      l->lcp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn]) * SECTICKS;
106236285Sbrian      if (arg->argc > arg->argn+1)
106336285Sbrian        l->ccp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn+1]) * SECTICKS;
106428461Sbrian    }
106528327Sbrian    return 0;
106628327Sbrian  }
106728327Sbrian  return -1;
106828327Sbrian}
106928327Sbrian
107031081Sbrian#define ismask(x) \
107131081Sbrian  (*x == '0' && strlen(x) == 4 && strspn(x+1, "0123456789.") == 3)
107231081Sbrian
107328327Sbrianstatic int
107431343SbrianSetServer(struct cmdargs const *arg)
107526940Sbrian{
107626940Sbrian  int res = -1;
107726940Sbrian
107836285Sbrian  if (arg->argc > arg->argn && arg->argc < arg->argn+4) {
107931081Sbrian    const char *port, *passwd, *mask;
108031081Sbrian
108131081Sbrian    /* What's what ? */
108236285Sbrian    port = arg->argv[arg->argn];
108336285Sbrian    if (arg->argc == arg->argn + 2) {
108436285Sbrian      passwd = arg->argv[arg->argn+1];
108536285Sbrian      mask = NULL;
108636285Sbrian    } else if (arg->argc == arg->argn + 3) {
108736285Sbrian      passwd = arg->argv[arg->argn+1];
108836285Sbrian      mask = arg->argv[arg->argn+2];
108931081Sbrian      if (!ismask(mask))
109031081Sbrian        return -1;
109136285Sbrian    } else if (strcasecmp(port, "none") == 0) {
109236285Sbrian      if (server_Close(arg->bundle))
109336285Sbrian        log_Printf(LogPHASE, "Disabled server port.\n");
109436285Sbrian      return 0;
109531081Sbrian    } else
109636285Sbrian      return -1;
109731081Sbrian
109836285Sbrian    strncpy(server.passwd, passwd, sizeof server.passwd - 1);
109936285Sbrian    server.passwd[sizeof server.passwd - 1] = '\0';
110031081Sbrian
110136285Sbrian    if (*port == '/') {
110231081Sbrian      mode_t imask;
110336285Sbrian      char *ptr, name[LINE_LEN + 12];
110428679Sbrian
110531081Sbrian      if (mask != NULL) {
110628679Sbrian	unsigned m;
110728679Sbrian
110831081Sbrian	if (sscanf(mask, "%o", &m) == 1)
110931081Sbrian	  imask = m;
111031081Sbrian        else
111131081Sbrian          return -1;
111231081Sbrian      } else
111331081Sbrian        imask = (mode_t)-1;
111436285Sbrian
111536285Sbrian      ptr = strstr(port, "%d");
111636285Sbrian      if (ptr) {
111736285Sbrian        snprintf(name, sizeof name, "%.*s%d%s",
111837210Sbrian                 (int)(ptr - port), port, arg->bundle->unit, ptr + 2);
111936285Sbrian        port = name;
112036285Sbrian      }
112136285Sbrian      res = server_LocalOpen(arg->bundle, port, imask);
112227346Sbrian    } else {
112336285Sbrian      int iport, add = 0;
112428679Sbrian
112531081Sbrian      if (mask != NULL)
112631081Sbrian        return -1;
112728679Sbrian
112836285Sbrian      if (*port == '+') {
112936285Sbrian        port++;
113036285Sbrian        add = 1;
113136285Sbrian      }
113231081Sbrian      if (strspn(port, "0123456789") != strlen(port)) {
113331081Sbrian        struct servent *s;
113431081Sbrian
113531081Sbrian        if ((s = getservbyname(port, "tcp")) == NULL) {
113631081Sbrian	  iport = 0;
113736285Sbrian	  log_Printf(LogWARN, "%s: Invalid port or service\n", port);
113828679Sbrian	} else
113931081Sbrian	  iport = ntohs(s->s_port);
114027346Sbrian      } else
114131081Sbrian        iport = atoi(port);
114236285Sbrian
114336285Sbrian      if (iport) {
114436285Sbrian        if (add)
114536285Sbrian          iport += arg->bundle->unit;
114636285Sbrian        res = server_TcpOpen(arg->bundle, iport);
114736285Sbrian      } else
114836285Sbrian        res = -1;
114927346Sbrian    }
115031081Sbrian  }
115126940Sbrian
115226940Sbrian  return res;
115326940Sbrian}
115426940Sbrian
115526940Sbrianstatic int
115631343SbrianSetModemParity(struct cmdargs const *arg)
11576059Samurai{
115836285Sbrian  return arg->argc > arg->argn ? modem_SetParity(arg->cx->physical,
115936285Sbrian                                                 arg->argv[arg->argn]) : -1;
11606059Samurai}
11616059Samurai
11626059Samuraistatic int
116331343SbrianSetEscape(struct cmdargs const *arg)
11646059Samurai{
11656059Samurai  int code;
116636285Sbrian  int argc = arg->argc - arg->argn;
116736285Sbrian  char const *const *argv = arg->argv + arg->argn;
11686059Samurai
11696059Samurai  for (code = 0; code < 33; code++)
117036285Sbrian    arg->cx->physical->async.cfg.EscMap[code] = 0;
117131343Sbrian
11726059Samurai  while (argc-- > 0) {
11736059Samurai    sscanf(*argv++, "%x", &code);
11746059Samurai    code &= 0xff;
117536285Sbrian    arg->cx->physical->async.cfg.EscMap[code >> 3] |= (1 << (code & 7));
117636285Sbrian    arg->cx->physical->async.cfg.EscMap[32] = 1;
11776059Samurai  }
117826516Sbrian  return 0;
11796059Samurai}
11806059Samurai
118130715Sbrianstatic struct in_addr
118231343SbrianGetIpAddr(const char *cp)
11836059Samurai{
11846059Samurai  struct hostent *hp;
11856059Samurai  struct in_addr ipaddr;
11866059Samurai
118732124Sbrian  if (inet_aton(cp, &ipaddr) == 0) {
118832124Sbrian    hp = gethostbyname(cp);
118932124Sbrian    if (hp && hp->h_addrtype == AF_INET)
119032124Sbrian      memcpy(&ipaddr, hp->h_addr, hp->h_length);
119132124Sbrian    else
119232124Sbrian      ipaddr.s_addr = 0;
119332124Sbrian  }
119428679Sbrian  return (ipaddr);
11956059Samurai}
11966059Samurai
11976059Samuraistatic int
119831343SbrianSetInterfaceAddr(struct cmdargs const *arg)
11996059Samurai{
120036285Sbrian  struct ipcp *ipcp = &arg->bundle->ncp.ipcp;
120132267Sbrian  const char *hisaddr;
120232267Sbrian
120332267Sbrian  hisaddr = NULL;
120436285Sbrian  ipcp->cfg.my_range.ipaddr.s_addr = INADDR_ANY;
120536285Sbrian  ipcp->cfg.peer_range.ipaddr.s_addr = INADDR_ANY;
12066059Samurai
120736285Sbrian  if (arg->argc > arg->argn + 4)
120828679Sbrian    return -1;
120926516Sbrian
121036285Sbrian  ipcp->cfg.HaveTriggerAddress = 0;
121136285Sbrian  ipcp->cfg.netmask.s_addr = INADDR_ANY;
121236285Sbrian  iplist_reset(&ipcp->cfg.peer_list);
121328394Sbrian
121436285Sbrian  if (arg->argc > arg->argn) {
121536285Sbrian    if (!ParseAddr(ipcp, arg->argc - arg->argn, arg->argv + arg->argn,
121636285Sbrian                   &ipcp->cfg.my_range.ipaddr, &ipcp->cfg.my_range.mask,
121736285Sbrian                   &ipcp->cfg.my_range.width))
121828679Sbrian      return 1;
121936285Sbrian    if (arg->argc > arg->argn+1) {
122036285Sbrian      hisaddr = arg->argv[arg->argn+1];
122136285Sbrian      if (arg->argc > arg->argn+2) {
122236285Sbrian        ipcp->cfg.netmask = GetIpAddr(arg->argv[arg->argn+2]);
122336285Sbrian	if (arg->argc > arg->argn+3) {
122436285Sbrian	  ipcp->cfg.TriggerAddress = GetIpAddr(arg->argv[arg->argn+3]);
122536285Sbrian	  ipcp->cfg.HaveTriggerAddress = 1;
12269440Samurai	}
12276059Samurai      }
12286059Samurai    }
12296059Samurai  }
123028394Sbrian
12316059Samurai  /*
12326059Samurai   * For backwards compatibility, 0.0.0.0 means any address.
12336059Samurai   */
123436285Sbrian  if (ipcp->cfg.my_range.ipaddr.s_addr == INADDR_ANY) {
123536285Sbrian    ipcp->cfg.my_range.mask.s_addr = INADDR_ANY;
123636285Sbrian    ipcp->cfg.my_range.width = 0;
12376059Samurai  }
123836285Sbrian  ipcp->my_ip.s_addr = ipcp->cfg.my_range.ipaddr.s_addr;
123936285Sbrian
124036285Sbrian  if (ipcp->cfg.peer_range.ipaddr.s_addr == INADDR_ANY) {
124136285Sbrian    ipcp->cfg.peer_range.mask.s_addr = INADDR_ANY;
124236285Sbrian    ipcp->cfg.peer_range.width = 0;
12436059Samurai  }
124428537Sbrian
124536285Sbrian  if (hisaddr && !ipcp_UseHisaddr(arg->bundle, hisaddr,
124636928Sbrian                                  arg->bundle->phys_type.all & PHYS_AUTO))
124732267Sbrian    return 4;
124831121Sbrian
124926516Sbrian  return 0;
12506059Samurai}
12516059Samurai
125218752Sjkhstatic int
125331343SbrianSetVariable(struct cmdargs const *arg)
12546059Samurai{
125537210Sbrian  long long_val, param = (long)arg->cmd->args;
125637210Sbrian  int mode, dummyint;
125731343Sbrian  const char *argp;
125836285Sbrian  struct datalink *cx = arg->cx;	/* LOCAL_CX uses this */
125936285Sbrian  const char *err = NULL;
126036285Sbrian  struct link *l = command_ChooseLink(arg);	/* LOCAL_CX_OPT uses this */
126136285Sbrian  struct in_addr dummyaddr, *addr;
12626059Samurai
126336285Sbrian  if (arg->argc > arg->argn)
126436285Sbrian    argp = arg->argv[arg->argn];
126526551Sbrian  else
126631343Sbrian    argp = "";
126726551Sbrian
126836285Sbrian  if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
126936285Sbrian    log_Printf(LogWARN, "set %s: No context (use the `link' command)\n",
127036285Sbrian              arg->cmd->name);
127136285Sbrian    return 1;
127236285Sbrian  } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
127336285Sbrian    log_Printf(LogWARN, "set %s: Redundant context (%s) ignored\n",
127436285Sbrian              arg->cmd->name, cx->name);
127536285Sbrian    cx = NULL;
127636285Sbrian  }
127736285Sbrian
127826551Sbrian  switch (param) {
127928679Sbrian  case VAR_AUTHKEY:
128036285Sbrian    if (bundle_Phase(arg->bundle) == PHASE_DEAD) {
128136285Sbrian      strncpy(arg->bundle->cfg.auth.key, argp,
128236285Sbrian              sizeof arg->bundle->cfg.auth.key - 1);
128336285Sbrian      arg->bundle->cfg.auth.key[sizeof arg->bundle->cfg.auth.key - 1] = '\0';
128436285Sbrian    } else {
128536285Sbrian      err = "set authkey: Only available at phase DEAD\n";
128636285Sbrian      log_Printf(LogWARN, err);
128736285Sbrian    }
128828679Sbrian    break;
128937210Sbrian
129028679Sbrian  case VAR_AUTHNAME:
129136285Sbrian    if (bundle_Phase(arg->bundle) == PHASE_DEAD) {
129236285Sbrian      strncpy(arg->bundle->cfg.auth.name, argp,
129336285Sbrian              sizeof arg->bundle->cfg.auth.name - 1);
129436285Sbrian      arg->bundle->cfg.auth.name[sizeof arg->bundle->cfg.auth.name - 1] = '\0';
129536285Sbrian    } else {
129636285Sbrian      err = "set authname: Only available at phase DEAD\n";
129736285Sbrian      log_Printf(LogWARN, err);
129836285Sbrian    }
129928679Sbrian    break;
130037210Sbrian
130136285Sbrian  case VAR_AUTOLOAD:
130236285Sbrian    if (arg->argc == arg->argn + 2 || arg->argc == arg->argn + 4) {
130336285Sbrian      arg->bundle->autoload.running = 1;
130436285Sbrian      arg->bundle->cfg.autoload.max.timeout = atoi(arg->argv[arg->argn]);
130536285Sbrian      arg->bundle->cfg.autoload.max.packets = atoi(arg->argv[arg->argn + 1]);
130636285Sbrian      if (arg->argc == arg->argn + 4) {
130736285Sbrian        arg->bundle->cfg.autoload.min.timeout = atoi(arg->argv[arg->argn + 2]);
130836285Sbrian        arg->bundle->cfg.autoload.min.packets = atoi(arg->argv[arg->argn + 3]);
130936285Sbrian      } else {
131036285Sbrian        arg->bundle->cfg.autoload.min.timeout = 0;
131136285Sbrian        arg->bundle->cfg.autoload.min.packets = 0;
131236285Sbrian      }
131336285Sbrian    } else {
131436285Sbrian      err = "Set autoload requires two or four arguments\n";
131536285Sbrian      log_Printf(LogWARN, err);
131636285Sbrian    }
131736285Sbrian    break;
131837210Sbrian
131928679Sbrian  case VAR_DIAL:
132036285Sbrian    strncpy(cx->cfg.script.dial, argp, sizeof cx->cfg.script.dial - 1);
132136285Sbrian    cx->cfg.script.dial[sizeof cx->cfg.script.dial - 1] = '\0';
132228679Sbrian    break;
132337210Sbrian
132428679Sbrian  case VAR_LOGIN:
132536285Sbrian    strncpy(cx->cfg.script.login, argp, sizeof cx->cfg.script.login - 1);
132636285Sbrian    cx->cfg.script.login[sizeof cx->cfg.script.login - 1] = '\0';
132728679Sbrian    break;
132837210Sbrian
132936285Sbrian  case VAR_WINSIZE:
133036285Sbrian    if (arg->argc > arg->argn) {
133136285Sbrian      l->ccp.cfg.deflate.out.winsize = atoi(arg->argv[arg->argn]);
133236285Sbrian      if (l->ccp.cfg.deflate.out.winsize < 8 ||
133336285Sbrian          l->ccp.cfg.deflate.out.winsize > 15) {
133436285Sbrian          log_Printf(LogWARN, "%d: Invalid outgoing window size\n",
133536285Sbrian                    l->ccp.cfg.deflate.out.winsize);
133636285Sbrian          l->ccp.cfg.deflate.out.winsize = 15;
133736285Sbrian      }
133836285Sbrian      if (arg->argc > arg->argn+1) {
133936285Sbrian        l->ccp.cfg.deflate.in.winsize = atoi(arg->argv[arg->argn+1]);
134036285Sbrian        if (l->ccp.cfg.deflate.in.winsize < 8 ||
134136285Sbrian            l->ccp.cfg.deflate.in.winsize > 15) {
134236285Sbrian            log_Printf(LogWARN, "%d: Invalid incoming window size\n",
134336285Sbrian                      l->ccp.cfg.deflate.in.winsize);
134436285Sbrian            l->ccp.cfg.deflate.in.winsize = 15;
134536285Sbrian        }
134636285Sbrian      } else
134736285Sbrian        l->ccp.cfg.deflate.in.winsize = 0;
134836285Sbrian    } else {
134936285Sbrian      err = "No window size specified\n";
135036285Sbrian      log_Printf(LogWARN, err);
135136285Sbrian    }
135236285Sbrian    break;
135337210Sbrian
135428679Sbrian  case VAR_DEVICE:
135536285Sbrian    physical_SetDeviceList(cx->physical, arg->argc - arg->argn,
135636285Sbrian                           arg->argv + arg->argn);
135736285Sbrian    break;
135837210Sbrian
135936285Sbrian  case VAR_ACCMAP:
136036285Sbrian    if (arg->argc > arg->argn) {
136137210Sbrian      u_long ulong_val;
136236285Sbrian      sscanf(argp, "%lx", &ulong_val);
136337210Sbrian      cx->physical->link.lcp.cfg.accmap = (u_int32_t)ulong_val;
136436285Sbrian    } else {
136536285Sbrian      err = "No accmap specified\n";
136636285Sbrian      log_Printf(LogWARN, err);
136736285Sbrian    }
136836285Sbrian    break;
136937210Sbrian
137036285Sbrian  case VAR_MODE:
137136285Sbrian    mode = Nam2mode(argp);
137236285Sbrian    if (mode == PHYS_NONE || mode == PHYS_ALL) {
137336285Sbrian      log_Printf(LogWARN, "%s: Invalid mode\n", argp);
137436285Sbrian      return -1;
137536285Sbrian    }
137636285Sbrian    bundle_SetMode(arg->bundle, cx, mode);
137736285Sbrian    break;
137837210Sbrian
137936285Sbrian  case VAR_MRRU:
138037210Sbrian    if (bundle_Phase(arg->bundle) != PHASE_DEAD) {
138136285Sbrian      log_Printf(LogWARN, "mrru: Only changable at phase DEAD\n");
138237210Sbrian      return 1;
138329696Sbrian    }
138437210Sbrian    long_val = atol(argp);
138537210Sbrian    if (long_val && long_val < MIN_MRU) {
138637210Sbrian      log_Printf(LogWARN, "MRRU %ld: too small - min %d\n", long_val, MIN_MRU);
138737210Sbrian      return 1;
138837210Sbrian    } else if (long_val > MAX_MRU) {
138937210Sbrian      log_Printf(LogWARN, "MRRU %ld: too big - max %d\n", long_val, MAX_MRU);
139037210Sbrian      return 1;
139137210Sbrian    } else
139237210Sbrian      arg->bundle->ncp.mp.cfg.mrru = long_val;
139328679Sbrian    break;
139437210Sbrian
139536285Sbrian  case VAR_MRU:
139637210Sbrian    long_val = atol(argp);
139737210Sbrian    if (long_val == 0)
139837210Sbrian      l->lcp.cfg.mru = DEF_MRU;
139937210Sbrian    else if (long_val < MIN_MRU) {
140037210Sbrian      log_Printf(LogWARN, "MRU %ld: too small - min %d\n", long_val, MIN_MRU);
140137210Sbrian      return 1;
140237210Sbrian    } else if (long_val > MAX_MRU) {
140337210Sbrian      log_Printf(LogWARN, "MRU %ld: too big - max %d\n", long_val, MAX_MRU);
140437210Sbrian      return 1;
140537210Sbrian    } else
140637210Sbrian      l->lcp.cfg.mru = long_val;
140728679Sbrian    break;
140837210Sbrian
140936285Sbrian  case VAR_MTU:
141037210Sbrian    long_val = atol(argp);
141137210Sbrian    if (long_val && long_val < MIN_MTU) {
141237210Sbrian      log_Printf(LogWARN, "MTU %ld: too small - min %d\n", long_val, MIN_MTU);
141337210Sbrian      return 1;
141437210Sbrian    } else if (long_val > MAX_MTU) {
141537210Sbrian      log_Printf(LogWARN, "MTU %ld: too big - max %d\n", long_val, MAX_MTU);
141637210Sbrian      return 1;
141737210Sbrian    } else
141837210Sbrian      arg->bundle->cfg.mtu = long_val;
141936285Sbrian    break;
142037210Sbrian
142136285Sbrian  case VAR_OPENMODE:
142236285Sbrian    if (strcasecmp(argp, "active") == 0)
142336285Sbrian      cx->physical->link.lcp.cfg.openmode = arg->argc > arg->argn+1 ?
142436285Sbrian        atoi(arg->argv[arg->argn+1]) : 1;
142536285Sbrian    else if (strcasecmp(argp, "passive") == 0)
142636285Sbrian      cx->physical->link.lcp.cfg.openmode = OPEN_PASSIVE;
142736285Sbrian    else {
142836285Sbrian      err = "%s: Invalid openmode\n";
142936285Sbrian      log_Printf(LogWARN, err, argp);
143036285Sbrian    }
143136285Sbrian    break;
143237210Sbrian
143328679Sbrian  case VAR_PHONE:
143436285Sbrian    strncpy(cx->cfg.phone.list, argp, sizeof cx->cfg.phone.list - 1);
143536285Sbrian    cx->cfg.phone.list[sizeof cx->cfg.phone.list - 1] = '\0';
143638174Sbrian    cx->phone.alt = cx->phone.next = NULL;
143728679Sbrian    break;
143837210Sbrian
143928679Sbrian  case VAR_HANGUP:
144036285Sbrian    strncpy(cx->cfg.script.hangup, argp, sizeof cx->cfg.script.hangup - 1);
144136285Sbrian    cx->cfg.script.hangup[sizeof cx->cfg.script.hangup - 1] = '\0';
144228679Sbrian    break;
144337210Sbrian
144436285Sbrian  case VAR_IDLETIMEOUT:
144536285Sbrian    if (arg->argc > arg->argn+1)
144636285Sbrian      err = "Too many idle timeout values\n";
144736285Sbrian    else if (arg->argc == arg->argn+1)
144836285Sbrian      bundle_SetIdleTimer(arg->bundle, atoi(argp));
144936285Sbrian    if (err)
145036285Sbrian      log_Printf(LogWARN, err);
145129549Sbrian    break;
145237210Sbrian
145336285Sbrian  case VAR_LQRPERIOD:
145437210Sbrian    long_val = atol(argp);
145537210Sbrian    if (long_val < MIN_LQRPERIOD) {
145637210Sbrian      log_Printf(LogWARN, "%ld: Invalid lqr period - min %d\n",
145737210Sbrian                 long_val, MIN_LQRPERIOD);
145837210Sbrian      return 1;
145936285Sbrian    } else
146037210Sbrian      l->lcp.cfg.lqrperiod = long_val;
146136285Sbrian    break;
146237210Sbrian
146336285Sbrian  case VAR_LCPRETRY:
146437210Sbrian    long_val = atol(argp);
146537210Sbrian    if (long_val < MIN_FSMRETRY) {
146637210Sbrian      log_Printf(LogWARN, "%ld: Invalid LCP FSM retry period - min %d\n",
146737210Sbrian                 long_val, MIN_FSMRETRY);
146837210Sbrian      return 1;
146936285Sbrian    } else
147037210Sbrian      cx->physical->link.lcp.cfg.fsmretry = long_val;
147136285Sbrian    break;
147237210Sbrian
147336285Sbrian  case VAR_CHAPRETRY:
147437210Sbrian    long_val = atol(argp);
147537210Sbrian    if (long_val < MIN_FSMRETRY) {
147637210Sbrian      log_Printf(LogWARN, "%ld: Invalid CHAP FSM retry period - min %d\n",
147737210Sbrian                 long_val, MIN_FSMRETRY);
147837210Sbrian      return 1;
147936285Sbrian    } else
148037210Sbrian      cx->chap.auth.cfg.fsmretry = long_val;
148136285Sbrian    break;
148237210Sbrian
148336285Sbrian  case VAR_PAPRETRY:
148437210Sbrian    long_val = atol(argp);
148537210Sbrian    if (long_val < MIN_FSMRETRY) {
148637210Sbrian      log_Printf(LogWARN, "%ld: Invalid PAP FSM retry period - min %d\n",
148737210Sbrian                 long_val, MIN_FSMRETRY);
148837210Sbrian      return 1;
148936285Sbrian    } else
149037210Sbrian      cx->pap.cfg.fsmretry = long_val;
149136285Sbrian    break;
149237210Sbrian
149336285Sbrian  case VAR_CCPRETRY:
149437210Sbrian    long_val = atol(argp);
149537210Sbrian    if (long_val < MIN_FSMRETRY) {
149637210Sbrian      log_Printf(LogWARN, "%ld: Invalid CCP FSM retry period - min %d\n",
149737210Sbrian                 long_val, MIN_FSMRETRY);
149837210Sbrian      return 1;
149936285Sbrian    } else
150037210Sbrian      l->ccp.cfg.fsmretry = long_val;
150136285Sbrian    break;
150237210Sbrian
150336285Sbrian  case VAR_IPCPRETRY:
150437210Sbrian    long_val = atol(argp);
150537210Sbrian    if (long_val < MIN_FSMRETRY) {
150637210Sbrian      log_Printf(LogWARN, "%ld: Invalid IPCP FSM retry period - min %d\n",
150737210Sbrian                 long_val, MIN_FSMRETRY);
150837210Sbrian      return 1;
150936285Sbrian    } else
151037210Sbrian      arg->bundle->ncp.ipcp.cfg.fsmretry = long_val;
151136285Sbrian    break;
151237210Sbrian
151336285Sbrian  case VAR_NBNS:
151436285Sbrian  case VAR_DNS:
151536285Sbrian    if (param == VAR_DNS)
151636285Sbrian      addr = arg->bundle->ncp.ipcp.cfg.ns.dns;
151736285Sbrian    else
151836285Sbrian      addr = arg->bundle->ncp.ipcp.cfg.ns.nbns;
151936285Sbrian
152036285Sbrian    addr[0].s_addr = addr[1].s_addr = INADDR_ANY;
152136285Sbrian
152236285Sbrian    if (arg->argc > arg->argn) {
152336285Sbrian      ParseAddr(&arg->bundle->ncp.ipcp, 1, arg->argv + arg->argn,
152436285Sbrian                addr, &dummyaddr, &dummyint);
152536285Sbrian      if (arg->argc > arg->argn+1)
152636285Sbrian        ParseAddr(&arg->bundle->ncp.ipcp, 1, arg->argv + arg->argn + 1,
152736285Sbrian                  addr + 1, &dummyaddr, &dummyint);
152836285Sbrian
152936285Sbrian      if (addr[1].s_addr == INADDR_ANY)
153036285Sbrian        addr[1].s_addr = addr[0].s_addr;
153136285Sbrian      if (addr[0].s_addr == INADDR_ANY)
153236285Sbrian        addr[0].s_addr = addr[1].s_addr;
153336285Sbrian    }
153436285Sbrian    break;
153538174Sbrian
153638174Sbrian  case VAR_CALLBACK:
153738174Sbrian    cx->cfg.callback.opmask = 0;
153838174Sbrian    for (dummyint = arg->argn; dummyint < arg->argc; dummyint++) {
153938174Sbrian      if (!strcasecmp(arg->argv[dummyint], "auth"))
154038174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_AUTH);
154138174Sbrian      else if (!strcasecmp(arg->argv[dummyint], "cbcp"))
154238174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_CBCP);
154338174Sbrian      else if (!strcasecmp(arg->argv[dummyint], "e.164")) {
154438174Sbrian        if (dummyint == arg->argc - 1)
154538174Sbrian          log_Printf(LogWARN, "No E.164 arg (E.164 ignored) !\n");
154638174Sbrian        else {
154738174Sbrian          cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_E164);
154838174Sbrian          strncpy(cx->cfg.callback.msg, arg->argv[++dummyint],
154938174Sbrian                  sizeof cx->cfg.callback.msg - 1);
155038174Sbrian          cx->cfg.callback.msg[sizeof cx->cfg.callback.msg - 1] = '\0';
155138174Sbrian        }
155238174Sbrian      } else if (!strcasecmp(arg->argv[dummyint], "none"))
155338174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_NONE);
155438174Sbrian      else
155538174Sbrian        return -1;
155638174Sbrian    }
155738174Sbrian    if (cx->cfg.callback.opmask == CALLBACK_BIT(CALLBACK_NONE))
155838174Sbrian      cx->cfg.callback.opmask = 0;
155938174Sbrian    break;
156038174Sbrian
156138174Sbrian  case VAR_CBCP:
156238174Sbrian    cx->cfg.cbcp.delay = 0;
156338174Sbrian    *cx->cfg.cbcp.phone = '\0';
156438174Sbrian    cx->cfg.cbcp.fsmretry = DEF_FSMRETRY;
156538174Sbrian    if (arg->argc > arg->argn) {
156638174Sbrian      strncpy(cx->cfg.cbcp.phone, arg->argv[arg->argn],
156738174Sbrian              sizeof cx->cfg.cbcp.phone - 1);
156838174Sbrian      cx->cfg.cbcp.phone[sizeof cx->cfg.cbcp.phone - 1] = '\0';
156938174Sbrian      if (arg->argc > arg->argn + 1) {
157038174Sbrian        cx->cfg.cbcp.delay = atoi(arg->argv[arg->argn + 1]);
157138174Sbrian        if (arg->argc > arg->argn + 2) {
157238174Sbrian          long_val = atol(arg->argv[arg->argn + 2]);
157338174Sbrian          if (long_val < MIN_FSMRETRY)
157438174Sbrian            log_Printf(LogWARN, "%ld: Invalid CBCP FSM retry period - min %d\n",
157538174Sbrian                       long_val, MIN_FSMRETRY);
157638174Sbrian          else
157738174Sbrian            cx->cfg.cbcp.fsmretry = long_val;
157838174Sbrian        }
157938174Sbrian      }
158038174Sbrian    }
158138174Sbrian    break;
158238544Sbrian
158338544Sbrian  case VAR_CHOKED:
158438544Sbrian    arg->bundle->cfg.choked.timeout = atoi(argp);
158538544Sbrian    if (arg->bundle->cfg.choked.timeout <= 0)
158638544Sbrian      arg->bundle->cfg.choked.timeout = CHOKED_TIMEOUT;
158738544Sbrian    break;
158838544Sbrian
15896059Samurai  }
159036285Sbrian
159136285Sbrian  return err ? 1 : 0;
15926059Samurai}
15936059Samurai
159428679Sbrianstatic int
159531343SbrianSetCtsRts(struct cmdargs const *arg)
159620812Sjkh{
159736285Sbrian  if (arg->argc == arg->argn+1) {
159836285Sbrian    if (strcmp(arg->argv[arg->argn], "on") == 0)
159936285Sbrian      physical_SetRtsCts(arg->cx->physical, 1);
160036285Sbrian    else if (strcmp(arg->argv[arg->argn], "off") == 0)
160136285Sbrian      physical_SetRtsCts(arg->cx->physical, 0);
160220812Sjkh    else
160326516Sbrian      return -1;
160426516Sbrian    return 0;
160520812Sjkh  }
160626516Sbrian  return -1;
160720812Sjkh}
160820812Sjkh
160930715Sbrianstatic struct cmdtab const SetCommands[] = {
161036285Sbrian  {"accmap", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
161136285Sbrian  "accmap value", "set accmap hex-value", (const void *)VAR_ACCMAP},
161228679Sbrian  {"authkey", "key", SetVariable, LOCAL_AUTH,
161336285Sbrian  "authentication key", "set authkey|key key", (const void *)VAR_AUTHKEY},
161428679Sbrian  {"authname", NULL, SetVariable, LOCAL_AUTH,
161536285Sbrian  "authentication name", "set authname name", (const void *)VAR_AUTHNAME},
161636285Sbrian  {"autoload", NULL, SetVariable, LOCAL_AUTH,
161736285Sbrian  "auto link [de]activation", "set autoload maxtime maxload mintime minload",
161836285Sbrian  (const void *)VAR_AUTOLOAD},
161938174Sbrian  {"callback", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
162038174Sbrian  "callback control", "set callback [none|auth|cbcp|"
162138174Sbrian  "E.164 *|number[,number]...]...", (const void *)VAR_CALLBACK},
162238174Sbrian  {"cbcp", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
162338174Sbrian  "CBCP control", "set cbcp [*|phone[,phone...] [delay [timeout]]]",
162438174Sbrian  (const void *)VAR_CBCP},
162536285Sbrian  {"ccpretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
162636285Sbrian  "FSM retry period", "set ccpretry value", (const void *)VAR_CCPRETRY},
162736285Sbrian  {"chapretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
162836285Sbrian  "CHAP retry period", "set chapretry value", (const void *)VAR_CHAPRETRY},
162938544Sbrian  {"choked", NULL, SetVariable, LOCAL_AUTH,
163038544Sbrian  "choked timeout", "set choked [secs]", (const void *)VAR_CHOKED},
163136285Sbrian  {"ctsrts", "crtscts", SetCtsRts, LOCAL_AUTH | LOCAL_CX,
163236285Sbrian  "Use hardware flow control", "set ctsrts [on|off]"},
163336285Sbrian  {"deflate", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
163436285Sbrian  "deflate window sizes", "set deflate out-winsize in-winsize",
163536285Sbrian  (const void *) VAR_WINSIZE},
163636285Sbrian  {"device", "line", SetVariable, LOCAL_AUTH | LOCAL_CX,
163736285Sbrian  "modem device name", "set device|line device-name[,device-name]",
163836285Sbrian  (const void *) VAR_DEVICE},
163936285Sbrian  {"dial", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
164036285Sbrian  "dialing script", "set dial chat-script", (const void *) VAR_DIAL},
164136285Sbrian  {"dns", NULL, SetVariable, LOCAL_AUTH, "Domain Name Server",
164236285Sbrian  "set dns pri-addr [sec-addr]", (const void *)VAR_DNS},
164336285Sbrian  {"enddisc", NULL, mp_SetEnddisc, LOCAL_AUTH,
164436285Sbrian  "Endpoint Discriminator", "set enddisc [IP|magic|label|psn value]"},
164536285Sbrian  {"escape", NULL, SetEscape, LOCAL_AUTH | LOCAL_CX,
164636285Sbrian  "escape characters", "set escape hex-digit ..."},
164736285Sbrian  {"filter", NULL, filter_Set, LOCAL_AUTH,
164836285Sbrian  "packet filters", "set filter alive|dial|in|out rule-no permit|deny "
164936285Sbrian  "[src_addr[/width]] [dst_addr[/width]] [tcp|udp|icmp [src [lt|eq|gt port]] "
165036285Sbrian  "[dst [lt|eq|gt port]] [estab] [syn] [finrst]]"},
165136285Sbrian  {"hangup", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
165236285Sbrian  "hangup script", "set hangup chat-script", (const void *) VAR_HANGUP},
165336285Sbrian  {"ifaddr", NULL, SetInterfaceAddr, LOCAL_AUTH, "destination address",
165431343Sbrian  "set ifaddr [src-addr [dst-addr [netmask [trg-addr]]]]"},
165536285Sbrian  {"ipcpretry", NULL, SetVariable, LOCAL_AUTH,
165636285Sbrian  "FSM retry period", "set ipcpretry value", (const void *)VAR_IPCPRETRY},
165736285Sbrian  {"lcpretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
165836285Sbrian  "FSM retry period", "set lcpretry value", (const void *)VAR_LCPRETRY},
165936712Sbrian  {"log", NULL, log_SetLevel, LOCAL_AUTH, "log level",
166038622Sbrian  "set log [local] [+|-]async|cbcp|ccp|chat|command|connect|debug|hdlc|id0|"
166138622Sbrian  "ipcp|lcp|lqm|phase|tcp/ip|timer|tun..."},
166236285Sbrian  {"login", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
166336285Sbrian  "login script", "set login chat-script", (const void *) VAR_LOGIN},
166436285Sbrian  {"lqrperiod", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
166536285Sbrian  "LQR period", "set lqrperiod value", (const void *)VAR_LQRPERIOD},
166636285Sbrian  {"mode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "mode value",
166736285Sbrian  "set mode interactive|auto|ddial|background", (const void *)VAR_MODE},
166836285Sbrian  {"mrru", NULL, SetVariable, LOCAL_AUTH, "MRRU value",
166936285Sbrian  "set mrru value", (const void *)VAR_MRRU},
167036285Sbrian  {"mru", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
167136285Sbrian  "MRU value", "set mru value", (const void *)VAR_MRU},
167236285Sbrian  {"mtu", NULL, SetVariable, LOCAL_AUTH,
167336285Sbrian  "interface MTU value", "set mtu value", (const void *)VAR_MTU},
167436285Sbrian  {"nbns", NULL, SetVariable, LOCAL_AUTH, "NetBIOS Name Server",
167536285Sbrian  "set nbns pri-addr [sec-addr]", (const void *)VAR_NBNS},
167636285Sbrian  {"openmode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "open mode",
167736285Sbrian  "set openmode active|passive [secs]", (const void *)VAR_OPENMODE},
167836285Sbrian  {"papretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
167936285Sbrian  "PAP retry period", "set papretry value", (const void *)VAR_PAPRETRY},
168036285Sbrian  {"parity", NULL, SetModemParity, LOCAL_AUTH | LOCAL_CX,
168136285Sbrian  "modem parity", "set parity [odd|even|none]"},
168236285Sbrian  {"phone", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "telephone number(s)",
168336285Sbrian  "set phone phone1[:phone2[...]]", (const void *)VAR_PHONE},
168436285Sbrian  {"reconnect", NULL, datalink_SetReconnect, LOCAL_AUTH | LOCAL_CX,
168536285Sbrian  "Reconnect timeout", "set reconnect value ntries"},
168636285Sbrian  {"redial", NULL, datalink_SetRedial, LOCAL_AUTH | LOCAL_CX,
168736285Sbrian  "Redial timeout", "set redial value|random[.value|random] [attempts]"},
168828679Sbrian  {"server", "socket", SetServer, LOCAL_AUTH,
168936774Sbrian  "server port", "set server|socket TcpPort|LocalName|none password [mask]"},
169036285Sbrian  {"speed", NULL, SetModemSpeed, LOCAL_AUTH | LOCAL_CX,
169136285Sbrian  "modem speed", "set speed value"},
169236285Sbrian  {"stopped", NULL, SetStoppedTimeout, LOCAL_AUTH | LOCAL_CX,
169336285Sbrian  "STOPPED timeouts", "set stopped [LCPseconds [CCPseconds]]"},
169436285Sbrian  {"timeout", NULL, SetVariable, LOCAL_AUTH, "Idle timeout",
169536285Sbrian  "set timeout idletime", (const void *)VAR_IDLETIMEOUT},
169636285Sbrian  {"vj", NULL, ipcp_vjset, LOCAL_AUTH,
169736285Sbrian  "vj values", "set vj slots|slotcomp [value]"},
169836285Sbrian  {"weight", NULL, mp_SetDatalinkWeight, LOCAL_AUTH | LOCAL_CX,
169936285Sbrian  "datalink weighting", "set weight n"},
170028679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
170131343Sbrian  "Display this message", "set help|? [command]", SetCommands},
170228679Sbrian  {NULL, NULL, NULL},
17036059Samurai};
17046059Samurai
17056059Samuraistatic int
170631343SbrianSetCommand(struct cmdargs const *arg)
17076059Samurai{
170836285Sbrian  if (arg->argc > arg->argn)
170936285Sbrian    FindExec(arg->bundle, SetCommands, arg->argc, arg->argn, arg->argv,
171036285Sbrian             arg->prompt, arg->cx);
171136285Sbrian  else if (arg->prompt)
171236285Sbrian    prompt_Printf(arg->prompt, "Use `set ?' to get a list or `set ? <var>' for"
171326516Sbrian	    " syntax help.\n");
17146059Samurai  else
171536285Sbrian    log_Printf(LogWARN, "set command must have arguments\n");
171626516Sbrian
171726516Sbrian  return 0;
17186059Samurai}
17196059Samurai
17206059Samurai
17216059Samuraistatic int
172231343SbrianAddCommand(struct cmdargs const *arg)
17236059Samurai{
17246059Samurai  struct in_addr dest, gateway, netmask;
172536285Sbrian  int gw, addrs;
17266059Samurai
172736285Sbrian  if (arg->argc != arg->argn+3 && arg->argc != arg->argn+2)
172831598Sbrian    return -1;
172931598Sbrian
173036285Sbrian  addrs = 0;
173136285Sbrian  if (arg->argc == arg->argn+2) {
173236285Sbrian    if (!strcasecmp(arg->argv[arg->argn], "default"))
173336285Sbrian      dest.s_addr = netmask.s_addr = INADDR_ANY;
173431598Sbrian    else {
173536285Sbrian      int width;
173636285Sbrian
173736285Sbrian      if (!ParseAddr(&arg->bundle->ncp.ipcp, 1, arg->argv + arg->argn,
173836285Sbrian	             &dest, &netmask, &width))
173936285Sbrian        return -1;
174036285Sbrian      if (!strncasecmp(arg->argv[arg->argn], "MYADDR", 6))
174136285Sbrian        addrs = ROUTE_DSTMYADDR;
174236285Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "HISADDR", 7))
174336285Sbrian        addrs = ROUTE_DSTHISADDR;
174431598Sbrian    }
174536285Sbrian    gw = 1;
174634536Sbrian  } else {
174736285Sbrian    if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
174836285Sbrian      addrs = ROUTE_DSTMYADDR;
174936285Sbrian      dest = arg->bundle->ncp.ipcp.my_ip;
175036285Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
175136285Sbrian      addrs = ROUTE_DSTHISADDR;
175236285Sbrian      dest = arg->bundle->ncp.ipcp.peer_ip;
175336285Sbrian    } else
175436285Sbrian      dest = GetIpAddr(arg->argv[arg->argn]);
175536285Sbrian    netmask = GetIpAddr(arg->argv[arg->argn+1]);
175631598Sbrian    gw = 2;
17576059Samurai  }
175836285Sbrian
175936285Sbrian  if (strcasecmp(arg->argv[arg->argn+gw], "HISADDR") == 0) {
176036285Sbrian    gateway = arg->bundle->ncp.ipcp.peer_ip;
176136285Sbrian    addrs |= ROUTE_GWHISADDR;
176236285Sbrian  } else if (strcasecmp(arg->argv[arg->argn+gw], "INTERFACE") == 0)
176331598Sbrian    gateway.s_addr = INADDR_ANY;
176431598Sbrian  else
176536285Sbrian    gateway = GetIpAddr(arg->argv[arg->argn+gw]);
176636285Sbrian
176736285Sbrian  if (bundle_SetRoute(arg->bundle, RTM_ADD, dest, gateway, netmask,
176837927Sbrian                  arg->cmd->args ? 1 : 0, (addrs & ROUTE_GWHISADDR) ? 1 : 0))
176936285Sbrian    route_Add(&arg->bundle->ncp.ipcp.route, addrs, dest, netmask, gateway);
177036285Sbrian
177131598Sbrian  return 0;
17726059Samurai}
17736059Samurai
17746059Samuraistatic int
177531343SbrianDeleteCommand(struct cmdargs const *arg)
17766059Samurai{
177731598Sbrian  struct in_addr dest, none;
177836285Sbrian  int addrs;
17796059Samurai
178036285Sbrian  if (arg->argc == arg->argn+1) {
178136285Sbrian    if(strcasecmp(arg->argv[arg->argn], "all") == 0) {
178236285Sbrian      route_IfDelete(arg->bundle, 0);
178336285Sbrian      route_DeleteAll(&arg->bundle->ncp.ipcp.route);
178436285Sbrian    } else {
178536285Sbrian      addrs = 0;
178636285Sbrian      if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
178736285Sbrian        dest = arg->bundle->ncp.ipcp.my_ip;
178836285Sbrian        addrs = ROUTE_DSTMYADDR;
178936285Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
179036285Sbrian        dest = arg->bundle->ncp.ipcp.peer_ip;
179136285Sbrian        addrs = ROUTE_DSTHISADDR;
179236285Sbrian      } else {
179336285Sbrian        if (strcasecmp(arg->argv[arg->argn], "default") == 0)
179436285Sbrian          dest.s_addr = INADDR_ANY;
179536285Sbrian        else
179636285Sbrian          dest = GetIpAddr(arg->argv[arg->argn]);
179736285Sbrian        addrs = ROUTE_STATIC;
179836285Sbrian      }
179931598Sbrian      none.s_addr = INADDR_ANY;
180036285Sbrian      bundle_SetRoute(arg->bundle, RTM_DELETE, dest, none, none,
180137927Sbrian                      arg->cmd->args ? 1 : 0, 0);
180236285Sbrian      route_Delete(&arg->bundle->ncp.ipcp.route, addrs, dest);
180331598Sbrian    }
180434536Sbrian  } else
180526516Sbrian    return -1;
180626516Sbrian
180726516Sbrian  return 0;
18086059Samurai}
18096059Samurai
181031343Sbrian#ifndef NOALIAS
181126031Sbrianstatic struct cmdtab const AliasCommands[] =
181226031Sbrian{
181336285Sbrian  {"addr", NULL, alias_RedirectAddr, LOCAL_AUTH,
181436285Sbrian   "static address translation", "alias addr [addr_local addr_alias]"},
181536285Sbrian  {"deny_incoming", NULL, AliasOption, LOCAL_AUTH,
181636285Sbrian   "stop incoming connections", "alias deny_incoming [yes|no]",
181736285Sbrian   (const void *) PKT_ALIAS_DENY_INCOMING},
181828679Sbrian  {"enable", NULL, AliasEnable, LOCAL_AUTH,
181936285Sbrian   "enable IP aliasing", "alias enable [yes|no]"},
182028679Sbrian  {"log", NULL, AliasOption, LOCAL_AUTH,
182136285Sbrian   "log aliasing link creation", "alias log [yes|no]",
182236285Sbrian   (const void *) PKT_ALIAS_LOG},
182336285Sbrian  {"port", NULL, alias_RedirectPort, LOCAL_AUTH,
182436285Sbrian   "port redirection", "alias port [proto addr_local:port_local  port_alias]"},
182528679Sbrian  {"same_ports", NULL, AliasOption, LOCAL_AUTH,
182636285Sbrian   "try to leave port numbers unchanged", "alias same_ports [yes|no]",
182736285Sbrian   (const void *) PKT_ALIAS_SAME_PORTS},
182836285Sbrian  {"unregistered_only", NULL, AliasOption, LOCAL_AUTH,
182936285Sbrian   "alias unregistered (private) IP address space only",
183036285Sbrian   "alias unregistered_only [yes|no]",
183136285Sbrian   (const void *) PKT_ALIAS_UNREGISTERED_ONLY},
183228679Sbrian  {"use_sockets", NULL, AliasOption, LOCAL_AUTH,
183336285Sbrian   "allocate host sockets", "alias use_sockets [yes|no]",
183436285Sbrian   (const void *) PKT_ALIAS_USE_SOCKETS},
183528679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
183636285Sbrian   "Display this message", "alias help|? [command]", AliasCommands},
183728679Sbrian  {NULL, NULL, NULL},
183826031Sbrian};
183926031Sbrian
184026031Sbrian
184126031Sbrianstatic int
184231343SbrianAliasCommand(struct cmdargs const *arg)
184326031Sbrian{
184436285Sbrian  if (arg->argc > arg->argn)
184536285Sbrian    FindExec(arg->bundle, AliasCommands, arg->argc, arg->argn, arg->argv,
184636285Sbrian             arg->prompt, arg->cx);
184736285Sbrian  else if (arg->prompt)
184836285Sbrian    prompt_Printf(arg->prompt, "Use `alias help' to get a list or `alias help"
184936285Sbrian            " <option>' for syntax help.\n");
185026031Sbrian  else
185136285Sbrian    log_Printf(LogWARN, "alias command must have arguments\n");
185226516Sbrian
185326516Sbrian  return 0;
185426031Sbrian}
185526031Sbrian
185626031Sbrianstatic int
185731343SbrianAliasEnable(struct cmdargs const *arg)
185826031Sbrian{
185936285Sbrian  if (arg->argc == arg->argn+1) {
186036285Sbrian    if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
186137191Sbrian      arg->bundle->AliasEnabled = 1;
186237191Sbrian      return 0;
186336285Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "no") == 0) {
186437191Sbrian      arg->bundle->AliasEnabled = 0;
186526516Sbrian      return 0;
186626142Sbrian    }
186735449Sbrian  }
186836285Sbrian
186926516Sbrian  return -1;
187026031Sbrian}
187126031Sbrian
187226031Sbrian
187326031Sbrianstatic int
187431343SbrianAliasOption(struct cmdargs const *arg)
187526031Sbrian{
187638559Sbrian  long param = (long)arg->cmd->args;
187738559Sbrian
187836285Sbrian  if (arg->argc == arg->argn+1) {
187936285Sbrian    if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
188037191Sbrian      if (arg->bundle->AliasEnabled) {
188137191Sbrian	PacketAliasSetMode(param, param);
188228679Sbrian	return 0;
188328679Sbrian      }
188436285Sbrian      log_Printf(LogWARN, "alias not enabled\n");
188536285Sbrian    } else if (strcmp(arg->argv[arg->argn], "no") == 0) {
188637191Sbrian      if (arg->bundle->AliasEnabled) {
188737191Sbrian	PacketAliasSetMode(0, param);
188828679Sbrian	return 0;
188928679Sbrian      }
189036285Sbrian      log_Printf(LogWARN, "alias not enabled\n");
189128679Sbrian    }
189235449Sbrian  }
189328679Sbrian  return -1;
189426031Sbrian}
189531343Sbrian#endif /* #ifndef NOALIAS */
189631121Sbrian
189731121Sbrianstatic struct cmdtab const AllowCommands[] = {
189836285Sbrian  {"modes", "mode", AllowModes, LOCAL_AUTH,
189936285Sbrian  "Only allow certain ppp modes", "allow modes mode..."},
190031121Sbrian  {"users", "user", AllowUsers, LOCAL_AUTH,
190131121Sbrian  "Allow users access to ppp", "allow users logname..."},
190231121Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
190331343Sbrian  "Display this message", "allow help|? [command]", AllowCommands},
190431121Sbrian  {NULL, NULL, NULL},
190531121Sbrian};
190631121Sbrian
190731121Sbrianstatic int
190831343SbrianAllowCommand(struct cmdargs const *arg)
190931121Sbrian{
191036285Sbrian  /* arg->bundle may be NULL (see system_IsValid()) ! */
191136285Sbrian  if (arg->argc > arg->argn)
191236285Sbrian    FindExec(arg->bundle, AllowCommands, arg->argc, arg->argn, arg->argv,
191336285Sbrian             arg->prompt, arg->cx);
191436285Sbrian  else if (arg->prompt)
191536285Sbrian    prompt_Printf(arg->prompt, "Use `allow ?' to get a list or `allow ? <cmd>'"
191636285Sbrian                  " for syntax help.\n");
191731121Sbrian  else
191836285Sbrian    log_Printf(LogWARN, "allow command must have arguments\n");
191931121Sbrian
192031121Sbrian  return 0;
192131121Sbrian}
192236285Sbrian
192336285Sbrianstatic int
192436285SbrianLinkCommand(struct cmdargs const *arg)
192536285Sbrian{
192636285Sbrian  if (arg->argc > arg->argn+1) {
192736285Sbrian    char namelist[LINE_LEN];
192836285Sbrian    struct datalink *cx;
192936285Sbrian    char *name;
193036285Sbrian    int result = 0;
193136285Sbrian
193236285Sbrian    if (!strcmp(arg->argv[arg->argn], "*")) {
193336285Sbrian      struct datalink *dl;
193436285Sbrian
193536285Sbrian      cx = arg->bundle->links;
193636285Sbrian      while (cx) {
193736285Sbrian        /* Watch it, the command could be a ``remove'' */
193836285Sbrian        dl = cx->next;
193936285Sbrian        FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
194036285Sbrian                 arg->prompt, cx);
194136285Sbrian        for (cx = arg->bundle->links; cx; cx = cx->next)
194236285Sbrian          if (cx == dl)
194336285Sbrian            break;		/* Pointer's still valid ! */
194436285Sbrian      }
194536285Sbrian    } else {
194636285Sbrian      strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
194736285Sbrian      namelist[sizeof namelist - 1] = '\0';
194836285Sbrian      for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
194936285Sbrian        if (!bundle2datalink(arg->bundle, name)) {
195036285Sbrian          log_Printf(LogWARN, "link: %s: Invalid link name\n", name);
195136285Sbrian          return 1;
195236285Sbrian        }
195336285Sbrian
195436285Sbrian      strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
195536285Sbrian      namelist[sizeof namelist - 1] = '\0';
195636285Sbrian      for(name = strtok(namelist, ", "); name; name = strtok(NULL,", ")) {
195736285Sbrian        cx = bundle2datalink(arg->bundle, name);
195836285Sbrian        if (cx)
195936285Sbrian          FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
196036285Sbrian                   arg->prompt, cx);
196136285Sbrian        else {
196236285Sbrian          log_Printf(LogWARN, "link: %s: Invalidated link name !\n", name);
196336285Sbrian          result++;
196436285Sbrian        }
196536285Sbrian      }
196636285Sbrian    }
196736285Sbrian    return result;
196836285Sbrian  }
196936285Sbrian
197036285Sbrian  log_Printf(LogWARN, "Usage: %s\n", arg->cmd->syntax);
197136285Sbrian  return 2;
197236285Sbrian}
197336285Sbrian
197436285Sbrianstruct link *
197536285Sbriancommand_ChooseLink(struct cmdargs const *arg)
197636285Sbrian{
197736285Sbrian  if (arg->cx)
197836285Sbrian    return &arg->cx->physical->link;
197937210Sbrian  else if (!arg->bundle->ncp.mp.cfg.mrru) {
198036285Sbrian    struct datalink *dl = bundle2datalink(arg->bundle, NULL);
198137210Sbrian    if (dl)
198237210Sbrian      return &dl->physical->link;
198336285Sbrian  }
198437210Sbrian  return &arg->bundle->ncp.mp.link;
198536285Sbrian}
198636285Sbrian
198736285Sbrianstatic const char *
198836285Sbrianident_cmd(const char *cmd, unsigned *keep, unsigned *add)
198936285Sbrian{
199036285Sbrian  const char *result;
199136285Sbrian
199236285Sbrian  switch (*cmd) {
199336285Sbrian    case 'A':
199436285Sbrian    case 'a':
199536285Sbrian      result = "accept";
199636285Sbrian      *keep = NEG_MYMASK;
199736285Sbrian      *add = NEG_ACCEPTED;
199836285Sbrian      break;
199936285Sbrian    case 'D':
200036285Sbrian    case 'd':
200136285Sbrian      switch (cmd[1]) {
200236285Sbrian        case 'E':
200336285Sbrian        case 'e':
200436285Sbrian          result = "deny";
200536285Sbrian          *keep = NEG_MYMASK;
200636285Sbrian          *add = 0;
200736285Sbrian          break;
200836285Sbrian        case 'I':
200936285Sbrian        case 'i':
201036285Sbrian          result = "disable";
201136285Sbrian          *keep = NEG_HISMASK;
201236285Sbrian          *add = 0;
201336285Sbrian          break;
201436285Sbrian        default:
201536285Sbrian          return NULL;
201636285Sbrian      }
201736285Sbrian      break;
201836285Sbrian    case 'E':
201936285Sbrian    case 'e':
202036285Sbrian      result = "enable";
202136285Sbrian      *keep = NEG_HISMASK;
202236285Sbrian      *add = NEG_ENABLED;
202336285Sbrian      break;
202436285Sbrian    default:
202536285Sbrian      return NULL;
202636285Sbrian  }
202736285Sbrian
202836285Sbrian  return result;
202936285Sbrian}
203036285Sbrian
203136285Sbrianstatic int
203236285SbrianOptSet(struct cmdargs const *arg)
203336285Sbrian{
203437574Sbrian  int bit = (int)(long)arg->cmd->args;
203536285Sbrian  const char *cmd;
203636285Sbrian  unsigned keep;			/* Keep these bits */
203736285Sbrian  unsigned add;				/* Add these bits */
203836285Sbrian
203936285Sbrian  if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL)
204036285Sbrian    return 1;
204136285Sbrian
204236285Sbrian  if (add)
204336285Sbrian    arg->bundle->cfg.opt |= bit;
204436285Sbrian  else
204536285Sbrian    arg->bundle->cfg.opt &= ~bit;
204636285Sbrian  return 0;
204736285Sbrian}
204836285Sbrian
204936285Sbrianstatic int
205036285SbrianNegotiateSet(struct cmdargs const *arg)
205136285Sbrian{
205237210Sbrian  long param = (long)arg->cmd->args;
205336285Sbrian  struct link *l = command_ChooseLink(arg);	/* LOCAL_CX_OPT uses this */
205436285Sbrian  struct datalink *cx = arg->cx;	/* LOCAL_CX uses this */
205536285Sbrian  const char *cmd;
205636285Sbrian  unsigned keep;			/* Keep these bits */
205736285Sbrian  unsigned add;				/* Add these bits */
205836285Sbrian
205936285Sbrian  if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL)
206036285Sbrian    return 1;
206136285Sbrian
206236285Sbrian  if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
206336285Sbrian    log_Printf(LogWARN, "%s %s: No context (use the `link' command)\n",
206436285Sbrian              cmd, arg->cmd->name);
206536285Sbrian    return 2;
206636285Sbrian  } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
206736285Sbrian    log_Printf(LogWARN, "%s %s: Redundant context (%s) ignored\n",
206836285Sbrian              cmd, arg->cmd->name, cx->name);
206936285Sbrian    cx = NULL;
207036285Sbrian  }
207136285Sbrian
207236285Sbrian  switch (param) {
207336285Sbrian    case NEG_ACFCOMP:
207436285Sbrian      cx->physical->link.lcp.cfg.acfcomp &= keep;
207536285Sbrian      cx->physical->link.lcp.cfg.acfcomp |= add;
207636285Sbrian      break;
207736285Sbrian    case NEG_CHAP:
207836285Sbrian      cx->physical->link.lcp.cfg.chap &= keep;
207936285Sbrian      cx->physical->link.lcp.cfg.chap |= add;
208036285Sbrian      break;
208136285Sbrian    case NEG_DEFLATE:
208236285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE] &= keep;
208336285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE] |= add;
208436285Sbrian      break;
208536285Sbrian    case NEG_DNS:
208636285Sbrian      arg->bundle->ncp.ipcp.cfg.ns.dns_neg &= keep;
208736285Sbrian      arg->bundle->ncp.ipcp.cfg.ns.dns_neg |= add;
208836285Sbrian      break;
208936285Sbrian    case NEG_LQR:
209036285Sbrian      cx->physical->link.lcp.cfg.lqr &= keep;
209136285Sbrian      cx->physical->link.lcp.cfg.lqr |= add;
209236285Sbrian      break;
209336285Sbrian    case NEG_PAP:
209436285Sbrian      cx->physical->link.lcp.cfg.pap &= keep;
209536285Sbrian      cx->physical->link.lcp.cfg.pap |= add;
209636285Sbrian      break;
209736285Sbrian    case NEG_PPPDDEFLATE:
209836285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE24] &= keep;
209936285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE24] |= add;
210036285Sbrian      break;
210136285Sbrian    case NEG_PRED1:
210236285Sbrian      l->ccp.cfg.neg[CCP_NEG_PRED1] &= keep;
210336285Sbrian      l->ccp.cfg.neg[CCP_NEG_PRED1] |= add;
210436285Sbrian      break;
210536285Sbrian    case NEG_PROTOCOMP:
210636285Sbrian      cx->physical->link.lcp.cfg.protocomp &= keep;
210736285Sbrian      cx->physical->link.lcp.cfg.protocomp |= add;
210836285Sbrian      break;
210936285Sbrian    case NEG_SHORTSEQ:
211036285Sbrian      if (bundle_Phase(arg->bundle) != PHASE_DEAD)
211136285Sbrian        log_Printf(LogWARN, "shortseq: Only changable at phase DEAD\n");
211236285Sbrian      else {
211336285Sbrian        arg->bundle->ncp.mp.cfg.shortseq &= keep;
211436285Sbrian        arg->bundle->ncp.mp.cfg.shortseq |= add;
211536285Sbrian      }
211636285Sbrian      break;
211736285Sbrian    case NEG_VJCOMP:
211836285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.neg &= keep;
211936285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.neg |= add;
212036285Sbrian      break;
212136285Sbrian  }
212236285Sbrian
212336285Sbrian  return 0;
212436285Sbrian}
212536285Sbrian
212636285Sbrianstatic struct cmdtab const NegotiateCommands[] = {
212736285Sbrian  {"idcheck", NULL, OptSet, LOCAL_AUTH, "Check FSM reply ids",
212836285Sbrian  "disable|enable", (const void *)OPT_IDCHECK},
212936285Sbrian  {"loopback", NULL, OptSet, LOCAL_AUTH, "Loop packets for local iface",
213036285Sbrian  "disable|enable", (const void *)OPT_LOOPBACK},
213136285Sbrian  {"passwdauth", NULL, OptSet, LOCAL_AUTH, "Use passwd file",
213236285Sbrian  "disable|enable", (const void *)OPT_PASSWDAUTH},
213336285Sbrian  {"proxy", NULL, OptSet, LOCAL_AUTH, "Create proxy ARP entry",
213436285Sbrian  "disable|enable", (const void *)OPT_PROXY},
213536285Sbrian  {"sroutes", NULL, OptSet, LOCAL_AUTH, "Use sticky routes",
213636285Sbrian  "disable|enable", (const void *)OPT_SROUTES},
213736285Sbrian  {"throughput", NULL, OptSet, LOCAL_AUTH, "Rolling throughput",
213836285Sbrian  "disable|enable", (const void *)OPT_THROUGHPUT},
213936285Sbrian  {"utmp", NULL, OptSet, LOCAL_AUTH, "Log connections in utmp",
214036285Sbrian  "disable|enable", (const void *)OPT_UTMP},
214136285Sbrian
214236285Sbrian#define OPT_MAX 7	/* accept/deny allowed below and not above */
214336285Sbrian
214436285Sbrian  {"acfcomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
214536285Sbrian  "Address & Control field compression", "accept|deny|disable|enable",
214636285Sbrian  (const void *)NEG_ACFCOMP},
214736285Sbrian  {"chap", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
214836285Sbrian  "Challenge Handshake Authentication Protocol", "accept|deny|disable|enable",
214936285Sbrian  (const void *)NEG_CHAP},
215036285Sbrian  {"deflate", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
215136285Sbrian  "Deflate compression", "accept|deny|disable|enable",
215236285Sbrian  (const void *)NEG_DEFLATE},
215336285Sbrian  {"deflate24", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
215436285Sbrian  "Deflate (type 24) compression", "accept|deny|disable|enable",
215536285Sbrian  (const void *)NEG_PPPDDEFLATE},
215636285Sbrian  {"dns", NULL, NegotiateSet, LOCAL_AUTH,
215736285Sbrian  "DNS specification", "accept|deny|disable|enable", (const void *)NEG_DNS},
215836285Sbrian  {"lqr", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
215936285Sbrian  "Link Quality Reports", "accept|deny|disable|enable",
216036285Sbrian  (const void *)NEG_LQR},
216136285Sbrian  {"pap", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
216236285Sbrian  "Password Authentication protocol", "accept|deny|disable|enable",
216336285Sbrian  (const void *)NEG_PAP},
216436285Sbrian  {"pred1", "predictor1", NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
216536285Sbrian  "Predictor 1 compression", "accept|deny|disable|enable",
216636285Sbrian  (const void *)NEG_PRED1},
216736285Sbrian  {"protocomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
216836285Sbrian  "Protocol field compression", "accept|deny|disable|enable",
216936285Sbrian  (const void *)NEG_PROTOCOMP},
217036285Sbrian  {"shortseq", NULL, NegotiateSet, LOCAL_AUTH,
217136285Sbrian  "MP Short Sequence Numbers", "accept|deny|disable|enable",
217236285Sbrian  (const void *)NEG_SHORTSEQ},
217336285Sbrian  {"vjcomp", NULL, NegotiateSet, LOCAL_AUTH,
217436285Sbrian  "Van Jacobson header compression", "accept|deny|disable|enable",
217536285Sbrian  (const void *)NEG_VJCOMP},
217636285Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
217736285Sbrian  "Display this message", "accept|deny|disable|enable help|? [value]",
217836285Sbrian  NegotiateCommands},
217936285Sbrian  {NULL, NULL, NULL},
218036285Sbrian};
218136285Sbrian
218236285Sbrianstatic int
218336285SbrianNegotiateCommand(struct cmdargs const *arg)
218436285Sbrian{
218536285Sbrian  if (arg->argc > arg->argn) {
218636285Sbrian    char const *argv[3];
218736285Sbrian    unsigned keep, add;
218836285Sbrian    int n;
218936285Sbrian
219036285Sbrian    if ((argv[0] = ident_cmd(arg->argv[arg->argn-1], &keep, &add)) == NULL)
219136285Sbrian      return -1;
219236285Sbrian    argv[2] = NULL;
219336285Sbrian
219436285Sbrian    for (n = arg->argn; n < arg->argc; n++) {
219536285Sbrian      argv[1] = arg->argv[n];
219636285Sbrian      FindExec(arg->bundle, NegotiateCommands + (keep == NEG_HISMASK ?
219736285Sbrian               0 : OPT_MAX), 2, 1, argv, arg->prompt, arg->cx);
219836285Sbrian    }
219936285Sbrian  } else if (arg->prompt)
220036285Sbrian    prompt_Printf(arg->prompt, "Use `%s ?' to get a list.\n",
220136285Sbrian	    arg->argv[arg->argn-1]);
220236285Sbrian  else
220336285Sbrian    log_Printf(LogWARN, "%s command must have arguments\n",
220436285Sbrian              arg->argv[arg->argn] );
220536285Sbrian
220636285Sbrian  return 0;
220736285Sbrian}
220836285Sbrian
220936285Sbrianconst char *
221036285Sbriancommand_ShowNegval(unsigned val)
221136285Sbrian{
221236285Sbrian  switch (val&3) {
221336285Sbrian    case 1: return "disabled & accepted";
221436285Sbrian    case 2: return "enabled & denied";
221536285Sbrian    case 3: return "enabled & accepted";
221636285Sbrian  }
221736285Sbrian  return "disabled & denied";
221836285Sbrian}
221936934Sbrian
222036934Sbrianstatic int
222136934SbrianClearCommand(struct cmdargs const *arg)
222236934Sbrian{
222336934Sbrian  struct pppThroughput *t;
222436934Sbrian  struct datalink *cx;
222536934Sbrian  int i, clear_type;
222636934Sbrian
222736934Sbrian  if (arg->argc < arg->argn + 1)
222836934Sbrian    return -1;
222936934Sbrian
223036934Sbrian  if (strcasecmp(arg->argv[arg->argn], "modem") == 0) {
223136934Sbrian    cx = arg->cx;
223236934Sbrian    if (!cx)
223336934Sbrian      cx = bundle2datalink(arg->bundle, NULL);
223436934Sbrian    if (!cx) {
223536934Sbrian      log_Printf(LogWARN, "A link must be specified for ``clear modem''\n");
223636934Sbrian      return 1;
223736934Sbrian    }
223836934Sbrian    t = &cx->physical->link.throughput;
223936934Sbrian  } else if (strcasecmp(arg->argv[arg->argn], "ipcp") == 0)
224036934Sbrian    t = &arg->bundle->ncp.ipcp.throughput;
224136934Sbrian  else
224236934Sbrian    return -1;
224336934Sbrian
224436934Sbrian  if (arg->argc > arg->argn + 1) {
224536934Sbrian    clear_type = 0;
224636934Sbrian    for (i = arg->argn + 1; i < arg->argc; i++)
224736934Sbrian      if (strcasecmp(arg->argv[i], "overall") == 0)
224836934Sbrian        clear_type |= THROUGHPUT_OVERALL;
224936934Sbrian      else if (strcasecmp(arg->argv[i], "current") == 0)
225036934Sbrian        clear_type |= THROUGHPUT_CURRENT;
225136934Sbrian      else if (strcasecmp(arg->argv[i], "peak") == 0)
225236934Sbrian        clear_type |= THROUGHPUT_PEAK;
225336934Sbrian      else
225436934Sbrian        return -1;
225536934Sbrian  } else
225636934Sbrian    clear_type = THROUGHPUT_ALL;
225736934Sbrian
225836934Sbrian  throughput_clear(t, clear_type, arg->prompt);
225936934Sbrian  return 0;
226036934Sbrian}
2261