command.c revision 40665
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 *
2040665Sbrian * $Id: command.c,v 1.170 1998/10/26 19:07:36 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"
8640561Sbrian#include "iface.h"
876059Samurai
8836285Sbrian/* ``set'' values */
8936285Sbrian#define	VAR_AUTHKEY	0
9036285Sbrian#define	VAR_DIAL	1
9136285Sbrian#define	VAR_LOGIN	2
9236285Sbrian#define	VAR_AUTHNAME	3
9336285Sbrian#define	VAR_AUTOLOAD	4
9436285Sbrian#define	VAR_WINSIZE	5
9536285Sbrian#define	VAR_DEVICE	6
9636285Sbrian#define	VAR_ACCMAP	7
9736285Sbrian#define	VAR_MRRU	8
9836285Sbrian#define	VAR_MRU		9
9936285Sbrian#define	VAR_MTU		10
10036285Sbrian#define	VAR_OPENMODE	11
10136285Sbrian#define	VAR_PHONE	12
10236285Sbrian#define	VAR_HANGUP	13
10336285Sbrian#define	VAR_IDLETIMEOUT	14
10436285Sbrian#define	VAR_LQRPERIOD	15
10536285Sbrian#define	VAR_LCPRETRY	16
10636285Sbrian#define	VAR_CHAPRETRY	17
10736285Sbrian#define	VAR_PAPRETRY	18
10836285Sbrian#define	VAR_CCPRETRY	19
10936285Sbrian#define	VAR_IPCPRETRY	20
11036285Sbrian#define	VAR_DNS		21
11136285Sbrian#define	VAR_NBNS	22
11236285Sbrian#define	VAR_MODE	23
11338174Sbrian#define	VAR_CALLBACK	24
11438174Sbrian#define	VAR_CBCP	25
11538544Sbrian#define	VAR_CHOKED	26
11640665Sbrian#define	VAR_SENDPIPE	27
11740665Sbrian#define	VAR_RECVPIPE	28
1186059Samurai
11936285Sbrian/* ``accept|deny|disable|enable'' masks */
12036285Sbrian#define NEG_HISMASK (1)
12136285Sbrian#define NEG_MYMASK (2)
12236285Sbrian
12336285Sbrian/* ``accept|deny|disable|enable'' values */
12436285Sbrian#define NEG_ACFCOMP	40
12536285Sbrian#define NEG_CHAP	41
12636285Sbrian#define NEG_DEFLATE	42
12736285Sbrian#define NEG_LQR		43
12836285Sbrian#define NEG_PAP		44
12936285Sbrian#define NEG_PPPDDEFLATE	45
13036285Sbrian#define NEG_PRED1	46
13136285Sbrian#define NEG_PROTOCOMP	47
13236285Sbrian#define NEG_SHORTSEQ	48
13336285Sbrian#define NEG_VJCOMP	49
13436285Sbrian#define NEG_DNS		50
13536285Sbrian
13637373Sbrianconst char Version[] = "2.0";
13740665Sbrianconst char VersionDate[] = "$Date: 1998/10/26 19:07:36 $";
13836285Sbrian
13936285Sbrianstatic int ShowCommand(struct cmdargs const *);
14036285Sbrianstatic int TerminalCommand(struct cmdargs const *);
14136285Sbrianstatic int QuitCommand(struct cmdargs const *);
14236285Sbrianstatic int OpenCommand(struct cmdargs const *);
14336285Sbrianstatic int CloseCommand(struct cmdargs const *);
14436285Sbrianstatic int DownCommand(struct cmdargs const *);
14536285Sbrianstatic int SetCommand(struct cmdargs const *);
14636285Sbrianstatic int LinkCommand(struct cmdargs const *);
14736285Sbrianstatic int AddCommand(struct cmdargs const *);
14836285Sbrianstatic int DeleteCommand(struct cmdargs const *);
14936285Sbrianstatic int NegotiateCommand(struct cmdargs const *);
15036934Sbrianstatic int ClearCommand(struct cmdargs const *);
15140561Sbrianstatic int RunListCommand(struct cmdargs const *);
15240561Sbrianstatic int IfaceAddCommand(struct cmdargs const *);
15340561Sbrianstatic int IfaceDeleteCommand(struct cmdargs const *);
15440561Sbrianstatic int IfaceClearCommand(struct cmdargs const *);
15531343Sbrian#ifndef NOALIAS
15636285Sbrianstatic int AliasEnable(struct cmdargs const *);
15736285Sbrianstatic int AliasOption(struct cmdargs const *);
15831343Sbrian#endif
1596059Samurai
16036285Sbrianstatic const char *
16136285Sbrianshowcx(struct cmdtab const *cmd)
16236285Sbrian{
16336285Sbrian  if (cmd->lauth & LOCAL_CX)
16436285Sbrian    return "(c)";
16536285Sbrian  else if (cmd->lauth & LOCAL_CX_OPT)
16636285Sbrian    return "(o)";
16736285Sbrian
16836285Sbrian  return "";
16936285Sbrian}
17036285Sbrian
1716059Samuraistatic int
17231343SbrianHelpCommand(struct cmdargs const *arg)
1736059Samurai{
17428679Sbrian  struct cmdtab const *cmd;
17536285Sbrian  int n, cmax, dmax, cols, cxlen;
17636285Sbrian  const char *cx;
1776059Samurai
17836285Sbrian  if (!arg->prompt) {
17936285Sbrian    log_Printf(LogWARN, "help: Cannot help without a prompt\n");
18026516Sbrian    return 0;
18136285Sbrian  }
18226516Sbrian
18336285Sbrian  if (arg->argc > arg->argn) {
18436285Sbrian    for (cmd = arg->cmdtab; cmd->name || cmd->alias; cmd++)
18536285Sbrian      if ((cmd->lauth & arg->prompt->auth) &&
18636285Sbrian          ((cmd->name && !strcasecmp(cmd->name, arg->argv[arg->argn])) ||
18736285Sbrian           (cmd->alias && !strcasecmp(cmd->alias, arg->argv[arg->argn])))) {
18836285Sbrian	prompt_Printf(arg->prompt, "%s %s\n", cmd->syntax, showcx(cmd));
18928679Sbrian	return 0;
1906059Samurai      }
19126516Sbrian    return -1;
1926059Samurai  }
19336285Sbrian
19431372Sbrian  cmax = dmax = 0;
19536285Sbrian  for (cmd = arg->cmdtab; cmd->func; cmd++)
19636285Sbrian    if (cmd->name && (cmd->lauth & arg->prompt->auth)) {
19736285Sbrian      if ((n = strlen(cmd->name) + strlen(showcx(cmd))) > cmax)
19831372Sbrian        cmax = n;
19931372Sbrian      if ((n = strlen(cmd->helpmes)) > dmax)
20031372Sbrian        dmax = n;
20131372Sbrian    }
20231372Sbrian
20331372Sbrian  cols = 80 / (dmax + cmax + 3);
2046059Samurai  n = 0;
20536285Sbrian  prompt_Printf(arg->prompt, "(o) = Optional context,"
20636285Sbrian                " (c) = Context required\n");
20736285Sbrian  for (cmd = arg->cmdtab; cmd->func; cmd++)
20836285Sbrian    if (cmd->name && (cmd->lauth & arg->prompt->auth)) {
20936285Sbrian      cx = showcx(cmd);
21036285Sbrian      cxlen = cmax - strlen(cmd->name);
21140482Sbrian      if (n % cols != 0)
21240482Sbrian        prompt_Printf(arg->prompt, " ");
21340482Sbrian      prompt_Printf(arg->prompt, "%s%-*.*s: %-*.*s",
21436285Sbrian              cmd->name, cxlen, cxlen, cx, dmax, dmax, cmd->helpmes);
21531372Sbrian      if (++n % cols == 0)
21636285Sbrian        prompt_Printf(arg->prompt, "\n");
2176059Samurai    }
21831372Sbrian  if (n % cols != 0)
21936285Sbrian    prompt_Printf(arg->prompt, "\n");
22026516Sbrian
22126516Sbrian  return 0;
2226059Samurai}
2236059Samurai
22436285Sbrianstatic int
22536285SbrianCloneCommand(struct cmdargs const *arg)
2266059Samurai{
22736285Sbrian  char namelist[LINE_LEN];
22836285Sbrian  char *name;
22936285Sbrian  int f;
2306059Samurai
23136285Sbrian  if (arg->argc == arg->argn)
23236285Sbrian    return -1;
23336285Sbrian
23436285Sbrian  namelist[sizeof namelist - 1] = '\0';
23536285Sbrian  for (f = arg->argn; f < arg->argc; f++) {
23636285Sbrian    strncpy(namelist, arg->argv[f], sizeof namelist - 1);
23736285Sbrian    for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
23836285Sbrian      bundle_DatalinkClone(arg->bundle, arg->cx, name);
2396059Samurai  }
24036285Sbrian
24136285Sbrian  return 0;
2426059Samurai}
2436059Samurai
2446059Samuraistatic int
24536285SbrianRemoveCommand(struct cmdargs const *arg)
2466059Samurai{
24736285Sbrian  if (arg->argc != arg->argn)
24836285Sbrian    return -1;
24911336Samurai
25036285Sbrian  if (arg->cx->state != DATALINK_CLOSED) {
25136285Sbrian    log_Printf(LogWARN, "remove: Cannot delete links that aren't closed\n");
25236285Sbrian    return 2;
2536059Samurai  }
25426516Sbrian
25536285Sbrian  bundle_DatalinkRemove(arg->bundle, arg->cx);
25636285Sbrian  return 0;
25736285Sbrian}
25832711Sbrian
25936285Sbrianstatic int
26036285SbrianRenameCommand(struct cmdargs const *arg)
26136285Sbrian{
26236285Sbrian  if (arg->argc != arg->argn + 1)
26336285Sbrian    return -1;
26431121Sbrian
26536285Sbrian  if (bundle_RenameDatalink(arg->bundle, arg->cx, arg->argv[arg->argn]))
26636285Sbrian    return 0;
26736285Sbrian
26836285Sbrian  log_Printf(LogWARN, "%s -> %s: target name already exists\n",
26936285Sbrian             arg->cx->name, arg->argv[arg->argn]);
27036285Sbrian  return 1;
27136285Sbrian}
27236285Sbrian
27336285Sbrianint
27436285SbrianLoadCommand(struct cmdargs const *arg)
27536285Sbrian{
27636285Sbrian  const char *name;
27736285Sbrian
27836285Sbrian  if (arg->argc > arg->argn)
27936285Sbrian    name = arg->argv[arg->argn];
28036285Sbrian  else
28136285Sbrian    name = "default";
28236285Sbrian
28336928Sbrian  if (!system_IsValid(name, arg->prompt, arg->bundle->phys_type.all)) {
28437019Sbrian    log_Printf(LogWARN, "%s: Label not allowed\n", name);
28536285Sbrian    return 1;
28636285Sbrian  } else {
28736285Sbrian    /*
28836285Sbrian     * Set the label before & after so that `set enddisc' works and
28936285Sbrian     * we handle nested `load' commands.
29036285Sbrian     */
29136285Sbrian    bundle_SetLabel(arg->bundle, arg->argc > arg->argn ? name : NULL);
29237008Sbrian    if (system_Select(arg->bundle, name, CONFFILE, arg->prompt, arg->cx) < 0) {
29336285Sbrian      bundle_SetLabel(arg->bundle, NULL);
29436285Sbrian      log_Printf(LogWARN, "%s: label not found.\n", name);
29536285Sbrian      return -1;
29632403Sbrian    }
29736285Sbrian    bundle_SetLabel(arg->bundle, arg->argc > arg->argn ? name : NULL);
29836285Sbrian  }
29926516Sbrian  return 0;
3006059Samurai}
3016059Samurai
30236285Sbrianint
30336285SbrianSaveCommand(struct cmdargs const *arg)
30436285Sbrian{
30536285Sbrian  log_Printf(LogWARN, "save command is not implemented (yet).\n");
30636285Sbrian  return 1;
30736285Sbrian}
30836285Sbrian
30910528Samuraistatic int
31036285SbrianDialCommand(struct cmdargs const *arg)
31128536Sbrian{
31236285Sbrian  int res;
31336285Sbrian
31436465Sbrian  if ((arg->cx && !(arg->cx->physical->type & (PHYS_INTERACTIVE|PHYS_AUTO)))
31536465Sbrian      || (!arg->cx &&
31636928Sbrian          (arg->bundle->phys_type.all & ~(PHYS_INTERACTIVE|PHYS_AUTO)))) {
31736285Sbrian    log_Printf(LogWARN, "Manual dial is only available for auto and"
31836285Sbrian              " interactive links\n");
31936285Sbrian    return 1;
32034536Sbrian  }
32136285Sbrian
32236285Sbrian  if (arg->argc > arg->argn && (res = LoadCommand(arg)) != 0)
32336285Sbrian    return res;
32436285Sbrian
32537993Sbrian  bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1);
32636285Sbrian
32736285Sbrian  return 0;
32828536Sbrian}
32928536Sbrian
33038628Sbrian#define isinword(ch) (isalnum(ch) || (ch) == '_')
33138628Sbrian
33238628Sbrianstatic char *
33338628Sbrianstrstrword(char *big, const char *little)
33438628Sbrian{
33538628Sbrian  /* Get the first occurance of the word ``little'' in ``big'' */
33638628Sbrian  char *pos;
33738628Sbrian  int len;
33838628Sbrian
33938628Sbrian  pos = big;
34038628Sbrian  len = strlen(little);
34138628Sbrian
34238628Sbrian  while ((pos = strstr(pos, little)) != NULL)
34338628Sbrian    if ((pos == big || !isinword(pos[-1])) && !isinword(pos[len]))
34438628Sbrian      break;
34538628Sbrian    else
34638628Sbrian      pos++;
34738628Sbrian
34838628Sbrian  return pos;
34938628Sbrian}
35038628Sbrian
35138628Sbrianstatic char *
35238628Sbriansubst(char *tgt, const char *oldstr, const char *newstr)
35338628Sbrian{
35438628Sbrian  /* tgt is a malloc()d area... realloc() as necessary */
35538628Sbrian  char *word, *ntgt;
35638628Sbrian  int ltgt, loldstr, lnewstr, pos;
35738628Sbrian
35838628Sbrian  if ((word = strstrword(tgt, oldstr)) == NULL)
35938628Sbrian    return tgt;
36038628Sbrian
36138628Sbrian  ltgt = strlen(tgt) + 1;
36238628Sbrian  loldstr = strlen(oldstr);
36338628Sbrian  lnewstr = strlen(newstr);
36438628Sbrian  do {
36538628Sbrian    pos = word - tgt;
36638628Sbrian    if (loldstr > lnewstr)
36738628Sbrian      bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr);
36838628Sbrian    if (loldstr != lnewstr) {
36938628Sbrian      ntgt = realloc(tgt, ltgt += lnewstr - loldstr);
37038628Sbrian      if (ntgt == NULL)
37138628Sbrian        break;			/* Oh wonderful ! */
37238628Sbrian      word = ntgt + pos;
37338628Sbrian      tgt = ntgt;
37438628Sbrian    }
37538628Sbrian    if (lnewstr > loldstr)
37638628Sbrian      bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr);
37738628Sbrian    bcopy(newstr, word, lnewstr);
37838628Sbrian  } while ((word = strstrword(word, oldstr)));
37938628Sbrian
38038628Sbrian  return tgt;
38138628Sbrian}
38238628Sbrian
38338628Sbrianstatic void
38438628Sbrianexpand(char **nargv, int argc, char const *const *oargv, struct bundle *bundle)
38538628Sbrian{
38638628Sbrian  int arg;
38738628Sbrian
38838628Sbrian  nargv[0] = strdup(oargv[0]);
38938628Sbrian  for (arg = 1; arg < argc; arg++) {
39038629Sbrian    nargv[arg] = strdup(oargv[arg]);
39138629Sbrian    nargv[arg] = subst(nargv[arg], "HISADDR",
39238628Sbrian                       inet_ntoa(bundle->ncp.ipcp.peer_ip));
39338629Sbrian    nargv[arg] = subst(nargv[arg], "AUTHNAME", bundle->cfg.auth.name);
39440561Sbrian    nargv[arg] = subst(nargv[arg], "INTERFACE", bundle->iface->name);
39538628Sbrian    nargv[arg] = subst(nargv[arg], "MYADDR", inet_ntoa(bundle->ncp.ipcp.my_ip));
39638629Sbrian    nargv[arg] = subst(nargv[arg], "USER", bundle->ncp.mp.peer.authname);
39738629Sbrian    nargv[arg] = subst(nargv[arg], "PEER_ENDDISC",
39838629Sbrian                       mp_Enddisc(bundle->ncp.mp.peer.enddisc.class,
39938629Sbrian                                  bundle->ncp.mp.peer.enddisc.address,
40038629Sbrian                                  bundle->ncp.mp.peer.enddisc.len));
40138629Sbrian    nargv[arg] = subst(nargv[arg], "ENDDISC",
40238629Sbrian                       mp_Enddisc(bundle->ncp.mp.cfg.enddisc.class,
40338629Sbrian                                  bundle->ncp.mp.cfg.enddisc.address,
40438629Sbrian                                  bundle->ncp.mp.cfg.enddisc.len));
40538629Sbrian    nargv[arg] = subst(nargv[arg], "LABEL", bundle_GetLabel(bundle));
40638628Sbrian  }
40738628Sbrian  nargv[arg] = NULL;
40838628Sbrian}
40938628Sbrian
41028536Sbrianstatic int
41131343SbrianShellCommand(struct cmdargs const *arg, int bg)
41210528Samurai{
41310528Samurai  const char *shell;
41410528Samurai  pid_t shpid;
41520813Sjkh
41618856Ssos#ifdef SHELL_ONLY_INTERACTIVELY
41726911Sbrian  /* we're only allowed to shell when we run ppp interactively */
41836285Sbrian  if (arg->prompt && arg->prompt->owner) {
41936285Sbrian    log_Printf(LogWARN, "Can't start a shell from a network connection\n");
42026516Sbrian    return 1;
42110528Samurai  }
42226911Sbrian#endif
42328679Sbrian
42436285Sbrian  if (arg->argc == arg->argn) {
42536285Sbrian    if (!arg->prompt) {
42636285Sbrian      log_Printf(LogWARN, "Can't start an interactive shell from"
42736285Sbrian                " a config file\n");
42828381Sbrian      return 1;
42936285Sbrian    } else if (arg->prompt->owner) {
43036285Sbrian      log_Printf(LogWARN, "Can't start an interactive shell from"
43136285Sbrian                " a socket connection\n");
43236285Sbrian      return 1;
43328381Sbrian    } else if (bg) {
43436285Sbrian      log_Printf(LogWARN, "Can only start an interactive shell in"
43528679Sbrian		" the foreground mode\n");
43628381Sbrian      return 1;
43728381Sbrian    }
43834536Sbrian  }
43934536Sbrian
44028679Sbrian  if ((shpid = fork()) == 0) {
44136285Sbrian    int i, fd;
44218531Sbde
44336285Sbrian    if ((shell = getenv("SHELL")) == 0)
44436285Sbrian      shell = _PATH_BSHELL;
44532017Sbrian
44636285Sbrian    timer_TermService();
44736285Sbrian
44836285Sbrian    if (arg->prompt)
44936285Sbrian      fd = arg->prompt->fd_out;
45036285Sbrian    else if ((fd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
45136285Sbrian      log_Printf(LogALERT, "Failed to open %s: %s\n",
45236285Sbrian                _PATH_DEVNULL, strerror(errno));
45328679Sbrian      exit(1);
45428679Sbrian    }
45528679Sbrian    for (i = 0; i < 3; i++)
45628679Sbrian      dup2(fd, i);
45726516Sbrian
45836285Sbrian    fcntl(3, F_SETFD, 1);	/* Set close-on-exec flag */
45926516Sbrian
46031061Sbrian    setuid(geteuid());
46136285Sbrian    if (arg->argc > arg->argn) {
46228679Sbrian      /* substitute pseudo args */
46338628Sbrian      char *argv[MAXARGS];
46438628Sbrian      int argc = arg->argc - arg->argn;
46538628Sbrian
46638628Sbrian      if (argc >= sizeof argv / sizeof argv[0]) {
46738628Sbrian        argc = sizeof argv / sizeof argv[0] - 1;
46838628Sbrian        log_Printf(LogWARN, "Truncating shell command to %d args\n", argc);
46931343Sbrian      }
47038628Sbrian      expand(argv, argc, arg->argv + arg->argn, arg->bundle);
47128679Sbrian      if (bg) {
47228679Sbrian	pid_t p;
47310528Samurai
47428679Sbrian	p = getpid();
47528679Sbrian	if (daemon(1, 1) == -1) {
47636832Sbrian	  log_Printf(LogERROR, "%d: daemon: %s\n", (int)p, strerror(errno));
47728679Sbrian	  exit(1);
47828679Sbrian	}
47936285Sbrian      } else if (arg->prompt)
48036285Sbrian        printf("ppp: Pausing until %s finishes\n", arg->argv[arg->argn]);
48131343Sbrian      execvp(argv[0], argv);
48230316Sbrian    } else {
48336285Sbrian      if (arg->prompt)
48432017Sbrian        printf("ppp: Pausing until %s finishes\n", shell);
48536285Sbrian      prompt_TtyOldMode(arg->prompt);
48631343Sbrian      execl(shell, shell, NULL);
48730316Sbrian    }
48820813Sjkh
48940665Sbrian    log_Printf(LogWARN, "exec() of %s failed: %s\n",
49040665Sbrian              arg->argc > arg->argn ? arg->argv[arg->argn] : shell,
49140665Sbrian              strerror(errno));
49228679Sbrian    exit(255);
49310528Samurai  }
49436285Sbrian
49536285Sbrian  if (shpid == (pid_t) - 1)
49636285Sbrian    log_Printf(LogERROR, "Fork failed: %s\n", strerror(errno));
49736285Sbrian  else {
49810528Samurai    int status;
49931343Sbrian    waitpid(shpid, &status, 0);
50010528Samurai  }
50120813Sjkh
50236285Sbrian  if (arg->prompt && !arg->prompt->owner)
50336285Sbrian    prompt_TtyCommandMode(arg->prompt);
50420813Sjkh
50536285Sbrian  return 0;
50610528Samurai}
50710528Samurai
50831343Sbrianstatic int
50931343SbrianBgShellCommand(struct cmdargs const *arg)
51031343Sbrian{
51136285Sbrian  if (arg->argc == arg->argn)
51231343Sbrian    return -1;
51331343Sbrian  return ShellCommand(arg, 1);
51431343Sbrian}
51531343Sbrian
51631343Sbrianstatic int
51731343SbrianFgShellCommand(struct cmdargs const *arg)
51831343Sbrian{
51931343Sbrian  return ShellCommand(arg, 0);
52031343Sbrian}
52131343Sbrian
52240561Sbrian#ifndef NOALIAS
52340561Sbrianstatic struct cmdtab const AliasCommands[] =
52440561Sbrian{
52540561Sbrian  {"addr", NULL, alias_RedirectAddr, LOCAL_AUTH,
52640561Sbrian   "static address translation", "alias addr [addr_local addr_alias]"},
52740561Sbrian  {"deny_incoming", NULL, AliasOption, LOCAL_AUTH,
52840561Sbrian   "stop incoming connections", "alias deny_incoming [yes|no]",
52940561Sbrian   (const void *) PKT_ALIAS_DENY_INCOMING},
53040561Sbrian  {"enable", NULL, AliasEnable, LOCAL_AUTH,
53140561Sbrian   "enable IP aliasing", "alias enable [yes|no]"},
53240561Sbrian  {"log", NULL, AliasOption, LOCAL_AUTH,
53340561Sbrian   "log aliasing link creation", "alias log [yes|no]",
53440561Sbrian   (const void *) PKT_ALIAS_LOG},
53540561Sbrian  {"port", NULL, alias_RedirectPort, LOCAL_AUTH,
53640561Sbrian   "port redirection", "alias port [proto addr_local:port_local  port_alias]"},
53740561Sbrian  {"same_ports", NULL, AliasOption, LOCAL_AUTH,
53840561Sbrian   "try to leave port numbers unchanged", "alias same_ports [yes|no]",
53940561Sbrian   (const void *) PKT_ALIAS_SAME_PORTS},
54040561Sbrian  {"unregistered_only", NULL, AliasOption, LOCAL_AUTH,
54140561Sbrian   "alias unregistered (private) IP address space only",
54240561Sbrian   "alias unregistered_only [yes|no]",
54340561Sbrian   (const void *) PKT_ALIAS_UNREGISTERED_ONLY},
54440561Sbrian  {"use_sockets", NULL, AliasOption, LOCAL_AUTH,
54540561Sbrian   "allocate host sockets", "alias use_sockets [yes|no]",
54640561Sbrian   (const void *) PKT_ALIAS_USE_SOCKETS},
54740561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
54840561Sbrian   "Display this message", "alias help|? [command]", AliasCommands},
54940561Sbrian  {NULL, NULL, NULL},
55040561Sbrian};
55140561Sbrian#endif
55240561Sbrian
55340561Sbrianstatic struct cmdtab const AllowCommands[] = {
55440561Sbrian  {"modes", "mode", AllowModes, LOCAL_AUTH,
55540561Sbrian  "Only allow certain ppp modes", "allow modes mode..."},
55640561Sbrian  {"users", "user", AllowUsers, LOCAL_AUTH,
55740561Sbrian  "Only allow ppp access to certain users", "allow users logname..."},
55840561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
55940561Sbrian  "Display this message", "allow help|? [command]", AllowCommands},
56040561Sbrian  {NULL, NULL, NULL},
56140561Sbrian};
56240561Sbrian
56340561Sbrianstatic struct cmdtab const IfaceCommands[] =
56440561Sbrian{
56540561Sbrian  {"add", NULL, IfaceAddCommand, LOCAL_AUTH,
56640561Sbrian   "Add iface address", "iface add addr[/bits| mask] peer", NULL},
56740561Sbrian  {NULL, "add!", IfaceAddCommand, LOCAL_AUTH,
56840561Sbrian   "Add or change an iface address", "iface add! addr[/bits| mask] peer",
56940561Sbrian   (void *)1},
57040561Sbrian  {"clear", NULL, IfaceClearCommand, LOCAL_AUTH,
57140561Sbrian   "Clear iface address(es)", "iface clear"},
57240561Sbrian  {"delete", "rm", IfaceDeleteCommand, LOCAL_AUTH,
57340561Sbrian   "Delete iface address", "iface delete addr", NULL},
57440561Sbrian  {NULL, "rm!", IfaceDeleteCommand, LOCAL_AUTH,
57540561Sbrian   "Delete iface address", "iface delete addr", (void *)1},
57640561Sbrian  {NULL, "delete!", IfaceDeleteCommand, LOCAL_AUTH,
57740561Sbrian   "Delete iface address", "iface delete addr", (void *)1},
57840561Sbrian  {"show", NULL, iface_Show, LOCAL_AUTH,
57940561Sbrian   "Show iface address(es)", "iface show"},
58040561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
58140561Sbrian   "Display this message", "alias help|? [command]", IfaceCommands},
58240561Sbrian  {NULL, NULL, NULL},
58340561Sbrian};
58440561Sbrian
58530715Sbrianstatic struct cmdtab const Commands[] = {
58636285Sbrian  {"accept", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
58728679Sbrian  "accept option request", "accept option .."},
58828679Sbrian  {"add", NULL, AddCommand, LOCAL_AUTH,
58932109Sbrian  "add route", "add dest mask gateway", NULL},
59036285Sbrian  {NULL, "add!", AddCommand, LOCAL_AUTH,
59132109Sbrian  "add or change route", "add! dest mask gateway", (void *)1},
59236285Sbrian#ifndef NOALIAS
59340561Sbrian  {"alias", NULL, RunListCommand, LOCAL_AUTH,
59440561Sbrian  "alias control", "alias option [yes|no]", AliasCommands},
59536285Sbrian#endif
59640561Sbrian  {"allow", "auth", RunListCommand, LOCAL_AUTH,
59740561Sbrian  "Allow ppp access", "allow users|modes ....", AllowCommands},
59828679Sbrian  {"bg", "!bg", BgShellCommand, LOCAL_AUTH,
59931372Sbrian  "Run a background command", "[!]bg command"},
60036934Sbrian  {"clear", NULL, ClearCommand, LOCAL_AUTH | LOCAL_CX_OPT,
60136934Sbrian  "Clear throughput statistics", "clear ipcp|modem [current|overall|peak]..."},
60236285Sbrian  {"clone", NULL, CloneCommand, LOCAL_AUTH | LOCAL_CX,
60336285Sbrian  "Clone a link", "clone newname..."},
60436285Sbrian  {"close", NULL, CloseCommand, LOCAL_AUTH | LOCAL_CX_OPT,
60536285Sbrian  "Close an FSM", "close [lcp|ccp]"},
60628679Sbrian  {"delete", NULL, DeleteCommand, LOCAL_AUTH,
60732109Sbrian  "delete route", "delete dest", NULL},
60836285Sbrian  {NULL, "delete!", DeleteCommand, LOCAL_AUTH,
60932109Sbrian  "delete a route if it exists", "delete! dest", (void *)1},
61036285Sbrian  {"deny", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
61128679Sbrian  "Deny option request", "deny option .."},
61236285Sbrian  {"dial", "call", DialCommand, LOCAL_AUTH | LOCAL_CX_OPT,
61337955Sbrian  "Dial and login", "dial|call [remote]", NULL},
61436285Sbrian  {"disable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
61528679Sbrian  "Disable option", "disable option .."},
61636285Sbrian  {"down", NULL, DownCommand, LOCAL_AUTH | LOCAL_CX_OPT,
61736285Sbrian  "Generate a down event", "down"},
61836285Sbrian  {"enable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
61928679Sbrian  "Enable option", "enable option .."},
62040561Sbrian  {"iface", "interface", RunListCommand, LOCAL_AUTH,
62140561Sbrian  "interface control", "iface option ...", IfaceCommands},
62236285Sbrian  {"link", "datalink", LinkCommand, LOCAL_AUTH,
62336285Sbrian  "Link specific commands", "link name command ..."},
62437008Sbrian  {"load", NULL, LoadCommand, LOCAL_AUTH | LOCAL_CX_OPT,
62528679Sbrian  "Load settings", "load [remote]"},
62636285Sbrian  {"open", NULL, OpenCommand, LOCAL_AUTH | LOCAL_CX_OPT,
62737955Sbrian  "Open an FSM", "open! [lcp|ccp|ipcp]", (void *)1},
62836285Sbrian  {"passwd", NULL, PasswdCommand, LOCAL_NO_AUTH,
62936285Sbrian  "Password for manipulation", "passwd LocalPassword"},
63036285Sbrian  {"quit", "bye", QuitCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
63136285Sbrian  "Quit PPP program", "quit|bye [all]"},
63236285Sbrian  {"remove", "rm", RemoveCommand, LOCAL_AUTH | LOCAL_CX,
63336285Sbrian  "Remove a link", "remove"},
63436285Sbrian  {"rename", "mv", RenameCommand, LOCAL_AUTH | LOCAL_CX,
63536285Sbrian  "Rename a link", "rename name"},
63628679Sbrian  {"save", NULL, SaveCommand, LOCAL_AUTH,
63728679Sbrian  "Save settings", "save"},
63836285Sbrian  {"set", "setup", SetCommand, LOCAL_AUTH | LOCAL_CX_OPT,
63928679Sbrian  "Set parameters", "set[up] var value"},
64028679Sbrian  {"shell", "!", FgShellCommand, LOCAL_AUTH,
64128679Sbrian  "Run a subshell", "shell|! [sh command]"},
64236285Sbrian  {"show", NULL, ShowCommand, LOCAL_AUTH | LOCAL_CX_OPT,
64331372Sbrian  "Show status and stats", "show var"},
64436285Sbrian  {"term", NULL, TerminalCommand, LOCAL_AUTH | LOCAL_CX,
64531372Sbrian  "Enter terminal mode", "term"},
64628679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
64731343Sbrian  "Display this message", "help|? [command]", Commands},
64828679Sbrian  {NULL, NULL, NULL},
6496059Samurai};
6506059Samurai
65128536Sbrianstatic int
65231343SbrianShowEscape(struct cmdargs const *arg)
6536059Samurai{
65436285Sbrian  if (arg->cx->physical->async.cfg.EscMap[32]) {
65536285Sbrian    int code, bit;
65636285Sbrian    const char *sep = "";
6576059Samurai
65826516Sbrian    for (code = 0; code < 32; code++)
65936285Sbrian      if (arg->cx->physical->async.cfg.EscMap[code])
66028679Sbrian	for (bit = 0; bit < 8; bit++)
66136285Sbrian	  if (arg->cx->physical->async.cfg.EscMap[code] & (1 << bit)) {
66236285Sbrian	    prompt_Printf(arg->prompt, "%s0x%02x", sep, (code << 3) + bit);
66336285Sbrian            sep = ", ";
66436285Sbrian          }
66536285Sbrian    prompt_Printf(arg->prompt, "\n");
6666059Samurai  }
66731077Sbrian  return 0;
6686059Samurai}
6696059Samurai
67028679Sbrianstatic int
67136285SbrianShowTimerList(struct cmdargs const *arg)
6726059Samurai{
67336285Sbrian  timer_Show(0, arg->prompt);
67431077Sbrian  return 0;
6756059Samurai}
6766059Samurai
67728679Sbrianstatic int
67831343SbrianShowStopped(struct cmdargs const *arg)
67928327Sbrian{
68036285Sbrian  prompt_Printf(arg->prompt, " Stopped Timer:  LCP: ");
68136285Sbrian  if (!arg->cx->physical->link.lcp.fsm.StoppedTimer.load)
68236285Sbrian    prompt_Printf(arg->prompt, "Disabled");
68328327Sbrian  else
68436285Sbrian    prompt_Printf(arg->prompt, "%ld secs",
68536285Sbrian                  arg->cx->physical->link.lcp.fsm.StoppedTimer.load / SECTICKS);
68628461Sbrian
68736285Sbrian  prompt_Printf(arg->prompt, ", CCP: ");
68836285Sbrian  if (!arg->cx->physical->link.ccp.fsm.StoppedTimer.load)
68936285Sbrian    prompt_Printf(arg->prompt, "Disabled");
69028461Sbrian  else
69136285Sbrian    prompt_Printf(arg->prompt, "%ld secs",
69236285Sbrian                  arg->cx->physical->link.ccp.fsm.StoppedTimer.load / SECTICKS);
69328461Sbrian
69436285Sbrian  prompt_Printf(arg->prompt, "\n");
69528461Sbrian
69631077Sbrian  return 0;
69728327Sbrian}
69828327Sbrian
69928679Sbrianstatic int
70031343SbrianShowVersion(struct cmdargs const *arg)
7016059Samurai{
70236285Sbrian  prompt_Printf(arg->prompt, "PPP Version %s - %s\n", Version, VersionDate);
70331077Sbrian  return 0;
7046059Samurai}
7056059Samurai
70628679Sbrianstatic int
70736285SbrianShowProtocolStats(struct cmdargs const *arg)
70826326Sbrian{
70936285Sbrian  struct link *l = command_ChooseLink(arg);
71026326Sbrian
71136285Sbrian  prompt_Printf(arg->prompt, "%s:\n", l->name);
71236285Sbrian  link_ReportProtocolStatus(l, arg->prompt);
71331077Sbrian  return 0;
71426326Sbrian}
71526326Sbrian
71630715Sbrianstatic struct cmdtab const ShowCommands[] = {
71736285Sbrian  {"bundle", NULL, bundle_ShowStatus, LOCAL_AUTH,
71836285Sbrian  "bundle details", "show bundle"},
71936285Sbrian  {"ccp", NULL, ccp_ReportStatus, LOCAL_AUTH | LOCAL_CX_OPT,
72036285Sbrian  "CCP status", "show cpp"},
72136285Sbrian  {"compress", NULL, sl_Show, LOCAL_AUTH,
72236285Sbrian  "VJ compression stats", "show compress"},
72336285Sbrian  {"escape", NULL, ShowEscape, LOCAL_AUTH | LOCAL_CX,
72436285Sbrian  "escape characters", "show escape"},
72536285Sbrian  {"filter", NULL, filter_Show, LOCAL_AUTH,
72636285Sbrian  "packet filters", "show filter [in|out|dial|alive]"},
72736285Sbrian  {"hdlc", NULL, hdlc_ReportStatus, LOCAL_AUTH | LOCAL_CX,
72836285Sbrian  "HDLC errors", "show hdlc"},
72940561Sbrian  {"iface", "interface", iface_Show, LOCAL_AUTH,
73040561Sbrian  "Interface status", "show iface"},
73136285Sbrian  {"ipcp", NULL, ipcp_Show, LOCAL_AUTH,
73236285Sbrian  "IPCP status", "show ipcp"},
73336285Sbrian  {"lcp", NULL, lcp_ReportStatus, LOCAL_AUTH | LOCAL_CX,
73436285Sbrian  "LCP status", "show lcp"},
73536285Sbrian  {"link", "datalink", datalink_Show, LOCAL_AUTH | LOCAL_CX,
73636285Sbrian  "(high-level) link info", "show link"},
73736285Sbrian  {"links", NULL, bundle_ShowLinks, LOCAL_AUTH,
73836285Sbrian  "available link names", "show links"},
73936285Sbrian  {"log", NULL, log_ShowLevel, LOCAL_AUTH,
74036285Sbrian  "log levels", "show log"},
74136285Sbrian  {"mem", NULL, mbuf_Show, LOCAL_AUTH,
74236285Sbrian  "mbuf allocations", "show mem"},
74336285Sbrian  {"modem", NULL, modem_ShowStatus, LOCAL_AUTH | LOCAL_CX,
74436285Sbrian  "(low-level) link info", "show modem"},
74536285Sbrian  {"mp", "multilink", mp_ShowStatus, LOCAL_AUTH,
74636285Sbrian  "multilink setup", "show mp"},
74736285Sbrian  {"proto", NULL, ShowProtocolStats, LOCAL_AUTH | LOCAL_CX_OPT,
74836285Sbrian  "protocol summary", "show proto"},
74936285Sbrian  {"route", NULL, route_Show, LOCAL_AUTH,
75036285Sbrian  "routing table", "show route"},
75136285Sbrian  {"stopped", NULL, ShowStopped, LOCAL_AUTH | LOCAL_CX,
75236285Sbrian  "STOPPED timeout", "show stopped"},
75336285Sbrian  {"timers", NULL, ShowTimerList, LOCAL_AUTH,
75436285Sbrian  "alarm timers", "show timers"},
75528679Sbrian  {"version", NULL, ShowVersion, LOCAL_NO_AUTH | LOCAL_AUTH,
75636285Sbrian  "version string", "show version"},
75736285Sbrian  {"who", NULL, log_ShowWho, LOCAL_AUTH,
75836285Sbrian  "client list", "show who"},
75928679Sbrian  {"help", "?", HelpCommand, LOCAL_NO_AUTH | LOCAL_AUTH,
76031343Sbrian  "Display this message", "show help|? [command]", ShowCommands},
76128679Sbrian  {NULL, NULL, NULL},
7626059Samurai};
7636059Samurai
76430715Sbrianstatic struct cmdtab const *
76531343SbrianFindCommand(struct cmdtab const *cmds, const char *str, int *pmatch)
7666059Samurai{
76726516Sbrian  int nmatch;
76826516Sbrian  int len;
76928679Sbrian  struct cmdtab const *found;
7706059Samurai
77126516Sbrian  found = NULL;
77226516Sbrian  len = strlen(str);
77326516Sbrian  nmatch = 0;
7746059Samurai  while (cmds->func) {
77525566Sbrian    if (cmds->name && strncasecmp(str, cmds->name, len) == 0) {
77626516Sbrian      if (cmds->name[len] == '\0') {
77728679Sbrian	*pmatch = 1;
77828679Sbrian	return cmds;
77926516Sbrian      }
7806059Samurai      nmatch++;
7816059Samurai      found = cmds;
78228679Sbrian    } else if (cmds->alias && strncasecmp(str, cmds->alias, len) == 0) {
78326516Sbrian      if (cmds->alias[len] == '\0') {
78428679Sbrian	*pmatch = 1;
78528679Sbrian	return cmds;
78626516Sbrian      }
7876059Samurai      nmatch++;
7886059Samurai      found = cmds;
7896059Samurai    }
7906059Samurai    cmds++;
7916059Samurai  }
7926059Samurai  *pmatch = nmatch;
79326516Sbrian  return found;
7946059Samurai}
7956059Samurai
79636285Sbrianstatic const char *
79736285SbrianmkPrefix(int argc, char const *const *argv, char *tgt, int sz)
79836285Sbrian{
79936285Sbrian  int f, tlen, len;
80036285Sbrian
80136285Sbrian  tlen = 0;
80236285Sbrian  for (f = 0; f < argc && tlen < sz - 2; f++) {
80336285Sbrian    if (f)
80436285Sbrian      tgt[tlen++] = ' ';
80536285Sbrian    len = strlen(argv[f]);
80636285Sbrian    if (len > sz - tlen - 1)
80736285Sbrian      len = sz - tlen - 1;
80836285Sbrian    strncpy(tgt+tlen, argv[f], len);
80936285Sbrian    tlen += len;
81036285Sbrian  }
81136285Sbrian  tgt[tlen] = '\0';
81236285Sbrian  return tgt;
81336285Sbrian}
81436285Sbrian
81530715Sbrianstatic int
81636285SbrianFindExec(struct bundle *bundle, struct cmdtab const *cmds, int argc, int argn,
81736285Sbrian         char const *const *argv, struct prompt *prompt, struct datalink *cx)
8186059Samurai{
81928679Sbrian  struct cmdtab const *cmd;
8206059Samurai  int val = 1;
8216059Samurai  int nmatch;
82231343Sbrian  struct cmdargs arg;
82336285Sbrian  char prefix[100];
8246059Samurai
82536285Sbrian  cmd = FindCommand(cmds, argv[argn], &nmatch);
8266059Samurai  if (nmatch > 1)
82736285Sbrian    log_Printf(LogWARN, "%s: Ambiguous command\n",
82836285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix));
82936285Sbrian  else if (cmd && (!prompt || (cmd->lauth & prompt->auth))) {
83036285Sbrian    if ((cmd->lauth & LOCAL_CX) && !cx)
83136285Sbrian      /* We've got no context, but we require it */
83236285Sbrian      cx = bundle2datalink(bundle, NULL);
83336285Sbrian
83436285Sbrian    if ((cmd->lauth & LOCAL_CX) && !cx)
83536285Sbrian      log_Printf(LogWARN, "%s: No context (use the `link' command)\n",
83636285Sbrian                mkPrefix(argn+1, argv, prefix, sizeof prefix));
83736285Sbrian    else {
83836285Sbrian      if (cx && !(cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
83936285Sbrian        log_Printf(LogWARN, "%s: Redundant context (%s) ignored\n",
84036285Sbrian                  mkPrefix(argn+1, argv, prefix, sizeof prefix), cx->name);
84136285Sbrian        cx = NULL;
84236285Sbrian      }
84336285Sbrian      arg.cmdtab = cmds;
84436285Sbrian      arg.cmd = cmd;
84536285Sbrian      arg.argc = argc;
84636285Sbrian      arg.argn = argn+1;
84736285Sbrian      arg.argv = argv;
84836285Sbrian      arg.bundle = bundle;
84936285Sbrian      arg.cx = cx;
85036285Sbrian      arg.prompt = prompt;
85136285Sbrian      val = (*cmd->func) (&arg);
85236285Sbrian    }
85331343Sbrian  } else
85436285Sbrian    log_Printf(LogWARN, "%s: Invalid command\n",
85536285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix));
85626516Sbrian
85726516Sbrian  if (val == -1)
85836285Sbrian    log_Printf(LogWARN, "Usage: %s\n", cmd->syntax);
85928679Sbrian  else if (val)
86036285Sbrian    log_Printf(LogWARN, "%s: Failed %d\n",
86136285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix), val);
86226516Sbrian
86326516Sbrian  return val;
8646059Samurai}
8656059Samurai
86637009Sbrianint
86737009Sbriancommand_Interpret(char *buff, int nb, char *argv[MAXARGS])
8686059Samurai{
8696059Samurai  char *cp;
8706059Samurai
8716059Samurai  if (nb > 0) {
8726059Samurai    cp = buff + strcspn(buff, "\r\n");
8736059Samurai    if (cp)
8746059Samurai      *cp = '\0';
87537009Sbrian    return MakeArgs(buff, argv, MAXARGS);
87637009Sbrian  }
87737009Sbrian  return 0;
87831121Sbrian}
8796059Samurai
88031822Sbrianstatic int
88131822Sbrianarghidden(int argc, char const *const *argv, int n)
88231822Sbrian{
88331822Sbrian  /* Is arg n of the given command to be hidden from the log ? */
88431828Sbrian
88531828Sbrian  /* set authkey xxxxx */
88631828Sbrian  /* set key xxxxx */
88731822Sbrian  if (n == 2 && !strncasecmp(argv[0], "se", 2) &&
88831822Sbrian      (!strncasecmp(argv[1], "authk", 5) || !strncasecmp(argv[1], "ke", 2)))
88931822Sbrian    return 1;
89031822Sbrian
89131828Sbrian  /* passwd xxxxx */
89231828Sbrian  if (n == 1 && !strncasecmp(argv[0], "p", 1))
89331828Sbrian    return 1;
89431828Sbrian
89536285Sbrian  /* set server port xxxxx .... */
89636285Sbrian  if (n == 3 && !strncasecmp(argv[0], "se", 2) &&
89736285Sbrian      !strncasecmp(argv[1], "se", 2))
89836285Sbrian    return 1;
89936285Sbrian
90031822Sbrian  return 0;
90131822Sbrian}
90231822Sbrian
90331121Sbrianvoid
90436285Sbriancommand_Run(struct bundle *bundle, int argc, char const *const *argv,
90537008Sbrian           struct prompt *prompt, const char *label, struct datalink *cx)
90631121Sbrian{
90731156Sbrian  if (argc > 0) {
90836285Sbrian    if (log_IsKept(LogCOMMAND)) {
90931156Sbrian      static char buf[LINE_LEN];
91031156Sbrian      int f, n;
91131156Sbrian
91231156Sbrian      *buf = '\0';
91331156Sbrian      if (label) {
91431962Sbrian        strncpy(buf, label, sizeof buf - 3);
91531962Sbrian        buf[sizeof buf - 3] = '\0';
91631156Sbrian        strcat(buf, ": ");
91731156Sbrian      }
91831156Sbrian      n = strlen(buf);
91931156Sbrian      for (f = 0; f < argc; f++) {
92031962Sbrian        if (n < sizeof buf - 1 && f)
92131156Sbrian          buf[n++] = ' ';
92231822Sbrian        if (arghidden(argc, argv, f))
92336285Sbrian          strncpy(buf+n, "********", sizeof buf - n - 1);
92431822Sbrian        else
92531962Sbrian          strncpy(buf+n, argv[f], sizeof buf - n - 1);
92631156Sbrian        n += strlen(buf+n);
92731156Sbrian      }
92836285Sbrian      log_Printf(LogCOMMAND, "%s\n", buf);
92931156Sbrian    }
93037008Sbrian    FindExec(bundle, Commands, argc, 0, argv, prompt, cx);
93131156Sbrian  }
9326059Samurai}
9336059Samurai
93431121Sbrianvoid
93536285Sbriancommand_Decode(struct bundle *bundle, char *buff, int nb, struct prompt *prompt,
93636285Sbrian              const char *label)
93731121Sbrian{
93831121Sbrian  int argc;
93937009Sbrian  char *argv[MAXARGS];
94031121Sbrian
94137009Sbrian  argc = command_Interpret(buff, nb, argv);
94237008Sbrian  command_Run(bundle, argc, (char const *const *)argv, prompt, label, NULL);
94331121Sbrian}
94431121Sbrian
9456059Samuraistatic int
94631343SbrianShowCommand(struct cmdargs const *arg)
9476059Samurai{
94836285Sbrian  if (!arg->prompt)
94936285Sbrian    log_Printf(LogWARN, "show: Cannot show without a prompt\n");
95036285Sbrian  else if (arg->argc > arg->argn)
95136285Sbrian    FindExec(arg->bundle, ShowCommands, arg->argc, arg->argn, arg->argv,
95236285Sbrian             arg->prompt, arg->cx);
9536059Samurai  else
95436285Sbrian    prompt_Printf(arg->prompt, "Use ``show ?'' to get a list.\n");
95526516Sbrian
95626516Sbrian  return 0;
9576059Samurai}
9586059Samurai
9596059Samuraistatic int
96031343SbrianTerminalCommand(struct cmdargs const *arg)
9616059Samurai{
96236285Sbrian  if (!arg->prompt) {
96336285Sbrian    log_Printf(LogWARN, "term: Need a prompt\n");
96426516Sbrian    return 1;
9656059Samurai  }
96636285Sbrian
96736285Sbrian  if (arg->cx->physical->link.lcp.fsm.state > ST_CLOSED) {
96836285Sbrian    prompt_Printf(arg->prompt, "LCP state is [%s]\n",
96936285Sbrian                  State2Nam(arg->cx->physical->link.lcp.fsm.state));
97036285Sbrian    return 1;
9716059Samurai  }
97236285Sbrian
97336285Sbrian  datalink_Up(arg->cx, 0, 0);
97436285Sbrian  prompt_TtyTermMode(arg->prompt, arg->cx);
97536285Sbrian  return 0;
9766059Samurai}
9776059Samurai
9786059Samuraistatic int
97931343SbrianQuitCommand(struct cmdargs const *arg)
9806059Samurai{
98136285Sbrian  if (!arg->prompt || prompt_IsController(arg->prompt) ||
98236285Sbrian      (arg->argc > arg->argn && !strcasecmp(arg->argv[arg->argn], "all") &&
98336285Sbrian       (arg->prompt->auth & LOCAL_AUTH)))
98436285Sbrian    Cleanup(EX_NORMAL);
98536285Sbrian  if (arg->prompt)
98636285Sbrian    prompt_Destroy(arg->prompt, 1);
98726516Sbrian
98826516Sbrian  return 0;
9896059Samurai}
9906059Samurai
9916059Samuraistatic int
99236285SbrianOpenCommand(struct cmdargs const *arg)
9936059Samurai{
99437160Sbrian  if (arg->argc == arg->argn)
99537993Sbrian    bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1);
99637160Sbrian  else if (arg->argc == arg->argn + 1) {
99737160Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp")) {
99837385Sbrian      struct datalink *cx = arg->cx ?
99937385Sbrian        arg->cx : bundle2datalink(arg->bundle, NULL);
100037385Sbrian      if (cx) {
100137385Sbrian        if (cx->physical->link.lcp.fsm.state == ST_OPENED)
100237385Sbrian          fsm_Reopen(&cx->physical->link.lcp.fsm);
100337160Sbrian        else
100437993Sbrian          bundle_Open(arg->bundle, cx->name, PHYS_ALL, 1);
100537160Sbrian      } else
100637160Sbrian        log_Printf(LogWARN, "open lcp: You must specify a link\n");
100737160Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) {
100837160Sbrian      struct fsm *fp;
10096059Samurai
101037210Sbrian      fp = &command_ChooseLink(arg)->ccp.fsm;
101137160Sbrian      if (fp->link->lcp.fsm.state != ST_OPENED)
101237160Sbrian        log_Printf(LogWARN, "open: LCP must be open before opening CCP\n");
101337160Sbrian      else if (fp->state == ST_OPENED)
101437160Sbrian        fsm_Reopen(fp);
101537160Sbrian      else {
101637160Sbrian        fp->open_mode = 0;	/* Not passive any more */
101737160Sbrian        if (fp->state == ST_STOPPED) {
101837160Sbrian          fsm_Down(fp);
101937160Sbrian          fsm_Up(fp);
102037160Sbrian        } else {
102137160Sbrian          fsm_Up(fp);
102237160Sbrian          fsm_Open(fp);
102337160Sbrian        }
102436285Sbrian      }
102537160Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ipcp")) {
102637160Sbrian      if (arg->cx)
102737160Sbrian        log_Printf(LogWARN, "open ipcp: You need not specify a link\n");
102837160Sbrian      if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED)
102937160Sbrian        fsm_Reopen(&arg->bundle->ncp.ipcp.fsm);
103037160Sbrian      else
103137993Sbrian        bundle_Open(arg->bundle, NULL, PHYS_ALL, 1);
103237160Sbrian    } else
103337160Sbrian      return -1;
103436285Sbrian  } else
103536285Sbrian    return -1;
103636285Sbrian
103726516Sbrian  return 0;
10386059Samurai}
10396059Samurai
104025067Sbrianstatic int
104136285SbrianCloseCommand(struct cmdargs const *arg)
10426059Samurai{
104337007Sbrian  if (arg->argc == arg->argn)
104437007Sbrian    bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_STAYDOWN);
104537007Sbrian  else if (arg->argc == arg->argn + 1) {
104637007Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp"))
104737007Sbrian      bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_LCP);
104837007Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "ccp") ||
104937007Sbrian             !strcasecmp(arg->argv[arg->argn], "ccp!")) {
105037007Sbrian      struct fsm *fp;
10516059Samurai
105237210Sbrian      fp = &command_ChooseLink(arg)->ccp.fsm;
105337007Sbrian      if (fp->state == ST_OPENED) {
105437007Sbrian        fsm_Close(fp);
105537007Sbrian        if (arg->argv[arg->argn][3] == '!')
105637007Sbrian          fp->open_mode = 0;		/* Stay ST_CLOSED */
105737007Sbrian        else
105837007Sbrian          fp->open_mode = OPEN_PASSIVE;	/* Wait for the peer to start */
105937007Sbrian      }
106037007Sbrian    } else
106136285Sbrian      return -1;
106236285Sbrian  } else
106336285Sbrian    return -1;
106436285Sbrian
106536285Sbrian  return 0;
10666059Samurai}
10676059Samurai
106825067Sbrianstatic int
106936285SbrianDownCommand(struct cmdargs const *arg)
107011336Samurai{
107137018Sbrian  if (arg->argc == arg->argn) {
107237018Sbrian      if (arg->cx)
107337018Sbrian        datalink_Down(arg->cx, CLOSE_STAYDOWN);
107437018Sbrian      else
107537018Sbrian        bundle_Down(arg->bundle, CLOSE_STAYDOWN);
107637018Sbrian  } else if (arg->argc == arg->argn + 1) {
107737018Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp")) {
107837018Sbrian      if (arg->cx)
107937018Sbrian        datalink_Down(arg->cx, CLOSE_LCP);
108037018Sbrian      else
108137018Sbrian        bundle_Down(arg->bundle, CLOSE_LCP);
108237018Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) {
108337018Sbrian      struct fsm *fp = arg->cx ? &arg->cx->physical->link.ccp.fsm :
108437018Sbrian                                 &arg->bundle->ncp.mp.link.ccp.fsm;
108537060Sbrian      fsm2initial(fp);
108637018Sbrian    } else
108737018Sbrian      return -1;
108836285Sbrian  } else
108936285Sbrian    return -1;
109036285Sbrian
109136285Sbrian  return 0;
109225067Sbrian}
109325067Sbrian
109425067Sbrianstatic int
109536285SbrianSetModemSpeed(struct cmdargs const *arg)
109625067Sbrian{
109736285Sbrian  long speed;
109836285Sbrian  char *end;
109911336Samurai
110036285Sbrian  if (arg->argc > arg->argn && *arg->argv[arg->argn]) {
110136285Sbrian    if (arg->argc > arg->argn+1) {
110236285Sbrian      log_Printf(LogWARN, "SetModemSpeed: Too many arguments");
110336285Sbrian      return -1;
110411336Samurai    }
110536285Sbrian    if (strcasecmp(arg->argv[arg->argn], "sync") == 0) {
110636285Sbrian      physical_SetSync(arg->cx->physical);
110736285Sbrian      return 0;
110836285Sbrian    }
110936285Sbrian    end = NULL;
111036285Sbrian    speed = strtol(arg->argv[arg->argn], &end, 10);
111136285Sbrian    if (*end) {
111236285Sbrian      log_Printf(LogWARN, "SetModemSpeed: Bad argument \"%s\"",
111336285Sbrian                arg->argv[arg->argn]);
111436285Sbrian      return -1;
111536285Sbrian    }
111636285Sbrian    if (physical_SetSpeed(arg->cx->physical, speed))
111736285Sbrian      return 0;
111836285Sbrian    log_Printf(LogWARN, "%s: Invalid speed\n", arg->argv[arg->argn]);
111936285Sbrian  } else
112036285Sbrian    log_Printf(LogWARN, "SetModemSpeed: No speed specified\n");
112124939Sbrian
112226516Sbrian  return -1;
112311336Samurai}
112411336Samurai
112525067Sbrianstatic int
112631343SbrianSetStoppedTimeout(struct cmdargs const *arg)
112728327Sbrian{
112836285Sbrian  struct link *l = &arg->cx->physical->link;
112936285Sbrian
113036285Sbrian  l->lcp.fsm.StoppedTimer.load = 0;
113136285Sbrian  l->ccp.fsm.StoppedTimer.load = 0;
113236285Sbrian  if (arg->argc <= arg->argn+2) {
113336285Sbrian    if (arg->argc > arg->argn) {
113436285Sbrian      l->lcp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn]) * SECTICKS;
113536285Sbrian      if (arg->argc > arg->argn+1)
113636285Sbrian        l->ccp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn+1]) * SECTICKS;
113728461Sbrian    }
113828327Sbrian    return 0;
113928327Sbrian  }
114028327Sbrian  return -1;
114128327Sbrian}
114228327Sbrian
114331081Sbrian#define ismask(x) \
114431081Sbrian  (*x == '0' && strlen(x) == 4 && strspn(x+1, "0123456789.") == 3)
114531081Sbrian
114628327Sbrianstatic int
114731343SbrianSetServer(struct cmdargs const *arg)
114826940Sbrian{
114926940Sbrian  int res = -1;
115026940Sbrian
115136285Sbrian  if (arg->argc > arg->argn && arg->argc < arg->argn+4) {
115231081Sbrian    const char *port, *passwd, *mask;
115331081Sbrian
115431081Sbrian    /* What's what ? */
115536285Sbrian    port = arg->argv[arg->argn];
115636285Sbrian    if (arg->argc == arg->argn + 2) {
115736285Sbrian      passwd = arg->argv[arg->argn+1];
115836285Sbrian      mask = NULL;
115936285Sbrian    } else if (arg->argc == arg->argn + 3) {
116036285Sbrian      passwd = arg->argv[arg->argn+1];
116136285Sbrian      mask = arg->argv[arg->argn+2];
116231081Sbrian      if (!ismask(mask))
116331081Sbrian        return -1;
116436285Sbrian    } else if (strcasecmp(port, "none") == 0) {
116536285Sbrian      if (server_Close(arg->bundle))
116636285Sbrian        log_Printf(LogPHASE, "Disabled server port.\n");
116736285Sbrian      return 0;
116831081Sbrian    } else
116936285Sbrian      return -1;
117031081Sbrian
117136285Sbrian    strncpy(server.passwd, passwd, sizeof server.passwd - 1);
117236285Sbrian    server.passwd[sizeof server.passwd - 1] = '\0';
117331081Sbrian
117436285Sbrian    if (*port == '/') {
117531081Sbrian      mode_t imask;
117636285Sbrian      char *ptr, name[LINE_LEN + 12];
117728679Sbrian
117831081Sbrian      if (mask != NULL) {
117928679Sbrian	unsigned m;
118028679Sbrian
118131081Sbrian	if (sscanf(mask, "%o", &m) == 1)
118231081Sbrian	  imask = m;
118331081Sbrian        else
118431081Sbrian          return -1;
118531081Sbrian      } else
118631081Sbrian        imask = (mode_t)-1;
118736285Sbrian
118836285Sbrian      ptr = strstr(port, "%d");
118936285Sbrian      if (ptr) {
119036285Sbrian        snprintf(name, sizeof name, "%.*s%d%s",
119137210Sbrian                 (int)(ptr - port), port, arg->bundle->unit, ptr + 2);
119236285Sbrian        port = name;
119336285Sbrian      }
119436285Sbrian      res = server_LocalOpen(arg->bundle, port, imask);
119527346Sbrian    } else {
119636285Sbrian      int iport, add = 0;
119728679Sbrian
119831081Sbrian      if (mask != NULL)
119931081Sbrian        return -1;
120028679Sbrian
120136285Sbrian      if (*port == '+') {
120236285Sbrian        port++;
120336285Sbrian        add = 1;
120436285Sbrian      }
120531081Sbrian      if (strspn(port, "0123456789") != strlen(port)) {
120631081Sbrian        struct servent *s;
120731081Sbrian
120831081Sbrian        if ((s = getservbyname(port, "tcp")) == NULL) {
120931081Sbrian	  iport = 0;
121036285Sbrian	  log_Printf(LogWARN, "%s: Invalid port or service\n", port);
121128679Sbrian	} else
121231081Sbrian	  iport = ntohs(s->s_port);
121327346Sbrian      } else
121431081Sbrian        iport = atoi(port);
121536285Sbrian
121636285Sbrian      if (iport) {
121736285Sbrian        if (add)
121836285Sbrian          iport += arg->bundle->unit;
121936285Sbrian        res = server_TcpOpen(arg->bundle, iport);
122036285Sbrian      } else
122136285Sbrian        res = -1;
122227346Sbrian    }
122331081Sbrian  }
122426940Sbrian
122526940Sbrian  return res;
122626940Sbrian}
122726940Sbrian
122826940Sbrianstatic int
122931343SbrianSetModemParity(struct cmdargs const *arg)
12306059Samurai{
123136285Sbrian  return arg->argc > arg->argn ? modem_SetParity(arg->cx->physical,
123236285Sbrian                                                 arg->argv[arg->argn]) : -1;
12336059Samurai}
12346059Samurai
12356059Samuraistatic int
123631343SbrianSetEscape(struct cmdargs const *arg)
12376059Samurai{
12386059Samurai  int code;
123936285Sbrian  int argc = arg->argc - arg->argn;
124036285Sbrian  char const *const *argv = arg->argv + arg->argn;
12416059Samurai
12426059Samurai  for (code = 0; code < 33; code++)
124336285Sbrian    arg->cx->physical->async.cfg.EscMap[code] = 0;
124431343Sbrian
12456059Samurai  while (argc-- > 0) {
12466059Samurai    sscanf(*argv++, "%x", &code);
12476059Samurai    code &= 0xff;
124836285Sbrian    arg->cx->physical->async.cfg.EscMap[code >> 3] |= (1 << (code & 7));
124936285Sbrian    arg->cx->physical->async.cfg.EscMap[32] = 1;
12506059Samurai  }
125126516Sbrian  return 0;
12526059Samurai}
12536059Samurai
125430715Sbrianstatic struct in_addr
125531343SbrianGetIpAddr(const char *cp)
12566059Samurai{
12576059Samurai  struct hostent *hp;
12586059Samurai  struct in_addr ipaddr;
12596059Samurai
126032124Sbrian  if (inet_aton(cp, &ipaddr) == 0) {
126132124Sbrian    hp = gethostbyname(cp);
126232124Sbrian    if (hp && hp->h_addrtype == AF_INET)
126332124Sbrian      memcpy(&ipaddr, hp->h_addr, hp->h_length);
126432124Sbrian    else
126532124Sbrian      ipaddr.s_addr = 0;
126632124Sbrian  }
126728679Sbrian  return (ipaddr);
12686059Samurai}
12696059Samurai
12706059Samuraistatic int
127131343SbrianSetInterfaceAddr(struct cmdargs const *arg)
12726059Samurai{
127336285Sbrian  struct ipcp *ipcp = &arg->bundle->ncp.ipcp;
127432267Sbrian  const char *hisaddr;
127532267Sbrian
127640561Sbrian  if (arg->argc > arg->argn + 4)
127740561Sbrian    return -1;
127840561Sbrian
127932267Sbrian  hisaddr = NULL;
128036285Sbrian  ipcp->cfg.my_range.ipaddr.s_addr = INADDR_ANY;
128136285Sbrian  ipcp->cfg.peer_range.ipaddr.s_addr = INADDR_ANY;
128236285Sbrian  ipcp->cfg.HaveTriggerAddress = 0;
128336285Sbrian  ipcp->cfg.netmask.s_addr = INADDR_ANY;
128436285Sbrian  iplist_reset(&ipcp->cfg.peer_list);
128528394Sbrian
128636285Sbrian  if (arg->argc > arg->argn) {
128736285Sbrian    if (!ParseAddr(ipcp, arg->argc - arg->argn, arg->argv + arg->argn,
128836285Sbrian                   &ipcp->cfg.my_range.ipaddr, &ipcp->cfg.my_range.mask,
128936285Sbrian                   &ipcp->cfg.my_range.width))
129028679Sbrian      return 1;
129136285Sbrian    if (arg->argc > arg->argn+1) {
129236285Sbrian      hisaddr = arg->argv[arg->argn+1];
129336285Sbrian      if (arg->argc > arg->argn+2) {
129436285Sbrian        ipcp->cfg.netmask = GetIpAddr(arg->argv[arg->argn+2]);
129536285Sbrian	if (arg->argc > arg->argn+3) {
129636285Sbrian	  ipcp->cfg.TriggerAddress = GetIpAddr(arg->argv[arg->argn+3]);
129736285Sbrian	  ipcp->cfg.HaveTriggerAddress = 1;
12989440Samurai	}
12996059Samurai      }
13006059Samurai    }
13016059Samurai  }
130228394Sbrian
130340561Sbrian  /* 0.0.0.0 means any address (0 bits) */
130436285Sbrian  if (ipcp->cfg.my_range.ipaddr.s_addr == INADDR_ANY) {
130536285Sbrian    ipcp->cfg.my_range.mask.s_addr = INADDR_ANY;
130636285Sbrian    ipcp->cfg.my_range.width = 0;
13076059Samurai  }
130836285Sbrian  ipcp->my_ip.s_addr = ipcp->cfg.my_range.ipaddr.s_addr;
130936285Sbrian
131036285Sbrian  if (hisaddr && !ipcp_UseHisaddr(arg->bundle, hisaddr,
131136928Sbrian                                  arg->bundle->phys_type.all & PHYS_AUTO))
131232267Sbrian    return 4;
131331121Sbrian
131426516Sbrian  return 0;
13156059Samurai}
13166059Samurai
131718752Sjkhstatic int
131831343SbrianSetVariable(struct cmdargs const *arg)
13196059Samurai{
132037210Sbrian  long long_val, param = (long)arg->cmd->args;
132137210Sbrian  int mode, dummyint;
132231343Sbrian  const char *argp;
132336285Sbrian  struct datalink *cx = arg->cx;	/* LOCAL_CX uses this */
132436285Sbrian  const char *err = NULL;
132536285Sbrian  struct link *l = command_ChooseLink(arg);	/* LOCAL_CX_OPT uses this */
132636285Sbrian  struct in_addr dummyaddr, *addr;
13276059Samurai
132836285Sbrian  if (arg->argc > arg->argn)
132936285Sbrian    argp = arg->argv[arg->argn];
133026551Sbrian  else
133131343Sbrian    argp = "";
133226551Sbrian
133336285Sbrian  if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
133436285Sbrian    log_Printf(LogWARN, "set %s: No context (use the `link' command)\n",
133536285Sbrian              arg->cmd->name);
133636285Sbrian    return 1;
133736285Sbrian  } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
133836285Sbrian    log_Printf(LogWARN, "set %s: Redundant context (%s) ignored\n",
133936285Sbrian              arg->cmd->name, cx->name);
134036285Sbrian    cx = NULL;
134136285Sbrian  }
134236285Sbrian
134326551Sbrian  switch (param) {
134428679Sbrian  case VAR_AUTHKEY:
134540622Sbrian    switch (bundle_Phase(arg->bundle)) {
134640622Sbrian      case PHASE_DEAD:
134740622Sbrian      case PHASE_ESTABLISH:
134840622Sbrian        strncpy(arg->bundle->cfg.auth.key, argp,
134940622Sbrian                sizeof arg->bundle->cfg.auth.key - 1);
135040622Sbrian        arg->bundle->cfg.auth.key[sizeof arg->bundle->cfg.auth.key - 1] = '\0';
135140622Sbrian        break;
135240622Sbrian      default:
135340622Sbrian        err = "set authkey: Only available at phase DEAD/ESTABLISH\n";
135440622Sbrian        log_Printf(LogWARN, err);
135540622Sbrian        break;
135636285Sbrian    }
135728679Sbrian    break;
135837210Sbrian
135928679Sbrian  case VAR_AUTHNAME:
136040622Sbrian    switch (bundle_Phase(arg->bundle)) {
136140622Sbrian      case PHASE_DEAD:
136240622Sbrian      case PHASE_ESTABLISH:
136340622Sbrian        strncpy(arg->bundle->cfg.auth.name, argp,
136440622Sbrian                sizeof arg->bundle->cfg.auth.name - 1);
136540622Sbrian        arg->bundle->cfg.auth.name[sizeof arg->bundle->cfg.auth.name-1] = '\0';
136640622Sbrian        break;
136740622Sbrian      default:
136840622Sbrian        err = "set authname: Only available at phase DEAD/ESTABLISH\n";
136940622Sbrian        log_Printf(LogWARN, err);
137040622Sbrian        break;
137136285Sbrian    }
137228679Sbrian    break;
137337210Sbrian
137436285Sbrian  case VAR_AUTOLOAD:
137536285Sbrian    if (arg->argc == arg->argn + 2 || arg->argc == arg->argn + 4) {
137636285Sbrian      arg->bundle->autoload.running = 1;
137736285Sbrian      arg->bundle->cfg.autoload.max.timeout = atoi(arg->argv[arg->argn]);
137836285Sbrian      arg->bundle->cfg.autoload.max.packets = atoi(arg->argv[arg->argn + 1]);
137936285Sbrian      if (arg->argc == arg->argn + 4) {
138036285Sbrian        arg->bundle->cfg.autoload.min.timeout = atoi(arg->argv[arg->argn + 2]);
138136285Sbrian        arg->bundle->cfg.autoload.min.packets = atoi(arg->argv[arg->argn + 3]);
138236285Sbrian      } else {
138336285Sbrian        arg->bundle->cfg.autoload.min.timeout = 0;
138436285Sbrian        arg->bundle->cfg.autoload.min.packets = 0;
138536285Sbrian      }
138636285Sbrian    } else {
138736285Sbrian      err = "Set autoload requires two or four arguments\n";
138836285Sbrian      log_Printf(LogWARN, err);
138936285Sbrian    }
139036285Sbrian    break;
139137210Sbrian
139228679Sbrian  case VAR_DIAL:
139336285Sbrian    strncpy(cx->cfg.script.dial, argp, sizeof cx->cfg.script.dial - 1);
139436285Sbrian    cx->cfg.script.dial[sizeof cx->cfg.script.dial - 1] = '\0';
139528679Sbrian    break;
139637210Sbrian
139728679Sbrian  case VAR_LOGIN:
139836285Sbrian    strncpy(cx->cfg.script.login, argp, sizeof cx->cfg.script.login - 1);
139936285Sbrian    cx->cfg.script.login[sizeof cx->cfg.script.login - 1] = '\0';
140028679Sbrian    break;
140137210Sbrian
140236285Sbrian  case VAR_WINSIZE:
140336285Sbrian    if (arg->argc > arg->argn) {
140436285Sbrian      l->ccp.cfg.deflate.out.winsize = atoi(arg->argv[arg->argn]);
140536285Sbrian      if (l->ccp.cfg.deflate.out.winsize < 8 ||
140636285Sbrian          l->ccp.cfg.deflate.out.winsize > 15) {
140736285Sbrian          log_Printf(LogWARN, "%d: Invalid outgoing window size\n",
140836285Sbrian                    l->ccp.cfg.deflate.out.winsize);
140936285Sbrian          l->ccp.cfg.deflate.out.winsize = 15;
141036285Sbrian      }
141136285Sbrian      if (arg->argc > arg->argn+1) {
141236285Sbrian        l->ccp.cfg.deflate.in.winsize = atoi(arg->argv[arg->argn+1]);
141336285Sbrian        if (l->ccp.cfg.deflate.in.winsize < 8 ||
141436285Sbrian            l->ccp.cfg.deflate.in.winsize > 15) {
141536285Sbrian            log_Printf(LogWARN, "%d: Invalid incoming window size\n",
141636285Sbrian                      l->ccp.cfg.deflate.in.winsize);
141736285Sbrian            l->ccp.cfg.deflate.in.winsize = 15;
141836285Sbrian        }
141936285Sbrian      } else
142036285Sbrian        l->ccp.cfg.deflate.in.winsize = 0;
142136285Sbrian    } else {
142236285Sbrian      err = "No window size specified\n";
142336285Sbrian      log_Printf(LogWARN, err);
142436285Sbrian    }
142536285Sbrian    break;
142637210Sbrian
142728679Sbrian  case VAR_DEVICE:
142836285Sbrian    physical_SetDeviceList(cx->physical, arg->argc - arg->argn,
142936285Sbrian                           arg->argv + arg->argn);
143036285Sbrian    break;
143137210Sbrian
143236285Sbrian  case VAR_ACCMAP:
143336285Sbrian    if (arg->argc > arg->argn) {
143437210Sbrian      u_long ulong_val;
143536285Sbrian      sscanf(argp, "%lx", &ulong_val);
143637210Sbrian      cx->physical->link.lcp.cfg.accmap = (u_int32_t)ulong_val;
143736285Sbrian    } else {
143836285Sbrian      err = "No accmap specified\n";
143936285Sbrian      log_Printf(LogWARN, err);
144036285Sbrian    }
144136285Sbrian    break;
144237210Sbrian
144336285Sbrian  case VAR_MODE:
144436285Sbrian    mode = Nam2mode(argp);
144536285Sbrian    if (mode == PHYS_NONE || mode == PHYS_ALL) {
144636285Sbrian      log_Printf(LogWARN, "%s: Invalid mode\n", argp);
144736285Sbrian      return -1;
144836285Sbrian    }
144936285Sbrian    bundle_SetMode(arg->bundle, cx, mode);
145036285Sbrian    break;
145137210Sbrian
145236285Sbrian  case VAR_MRRU:
145340622Sbrian    switch (bundle_Phase(arg->bundle)) {
145440622Sbrian      case PHASE_DEAD:
145540622Sbrian        break;
145640622Sbrian      case PHASE_ESTABLISH:
145740622Sbrian        /* Make sure none of our links are DATALINK_LCP or greater */
145840622Sbrian        if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) {
145940622Sbrian          log_Printf(LogWARN, "mrru: Only changable before LCP negotiations\n");
146040622Sbrian          return 1;
146140622Sbrian        }
146240622Sbrian        break;
146340622Sbrian      default:
146440622Sbrian        log_Printf(LogWARN, "mrru: Only changable at phase DEAD/ESTABLISH\n");
146540622Sbrian        return 1;
146629696Sbrian    }
146737210Sbrian    long_val = atol(argp);
146837210Sbrian    if (long_val && long_val < MIN_MRU) {
146937210Sbrian      log_Printf(LogWARN, "MRRU %ld: too small - min %d\n", long_val, MIN_MRU);
147037210Sbrian      return 1;
147137210Sbrian    } else if (long_val > MAX_MRU) {
147237210Sbrian      log_Printf(LogWARN, "MRRU %ld: too big - max %d\n", long_val, MAX_MRU);
147337210Sbrian      return 1;
147437210Sbrian    } else
147537210Sbrian      arg->bundle->ncp.mp.cfg.mrru = long_val;
147628679Sbrian    break;
147737210Sbrian
147836285Sbrian  case VAR_MRU:
147937210Sbrian    long_val = atol(argp);
148037210Sbrian    if (long_val == 0)
148137210Sbrian      l->lcp.cfg.mru = DEF_MRU;
148237210Sbrian    else if (long_val < MIN_MRU) {
148337210Sbrian      log_Printf(LogWARN, "MRU %ld: too small - min %d\n", long_val, MIN_MRU);
148437210Sbrian      return 1;
148537210Sbrian    } else if (long_val > MAX_MRU) {
148637210Sbrian      log_Printf(LogWARN, "MRU %ld: too big - max %d\n", long_val, MAX_MRU);
148737210Sbrian      return 1;
148837210Sbrian    } else
148937210Sbrian      l->lcp.cfg.mru = long_val;
149028679Sbrian    break;
149137210Sbrian
149236285Sbrian  case VAR_MTU:
149337210Sbrian    long_val = atol(argp);
149437210Sbrian    if (long_val && long_val < MIN_MTU) {
149537210Sbrian      log_Printf(LogWARN, "MTU %ld: too small - min %d\n", long_val, MIN_MTU);
149637210Sbrian      return 1;
149737210Sbrian    } else if (long_val > MAX_MTU) {
149837210Sbrian      log_Printf(LogWARN, "MTU %ld: too big - max %d\n", long_val, MAX_MTU);
149937210Sbrian      return 1;
150037210Sbrian    } else
150137210Sbrian      arg->bundle->cfg.mtu = long_val;
150236285Sbrian    break;
150337210Sbrian
150436285Sbrian  case VAR_OPENMODE:
150536285Sbrian    if (strcasecmp(argp, "active") == 0)
150636285Sbrian      cx->physical->link.lcp.cfg.openmode = arg->argc > arg->argn+1 ?
150736285Sbrian        atoi(arg->argv[arg->argn+1]) : 1;
150836285Sbrian    else if (strcasecmp(argp, "passive") == 0)
150936285Sbrian      cx->physical->link.lcp.cfg.openmode = OPEN_PASSIVE;
151036285Sbrian    else {
151136285Sbrian      err = "%s: Invalid openmode\n";
151236285Sbrian      log_Printf(LogWARN, err, argp);
151336285Sbrian    }
151436285Sbrian    break;
151537210Sbrian
151628679Sbrian  case VAR_PHONE:
151736285Sbrian    strncpy(cx->cfg.phone.list, argp, sizeof cx->cfg.phone.list - 1);
151836285Sbrian    cx->cfg.phone.list[sizeof cx->cfg.phone.list - 1] = '\0';
151938174Sbrian    cx->phone.alt = cx->phone.next = NULL;
152028679Sbrian    break;
152137210Sbrian
152228679Sbrian  case VAR_HANGUP:
152336285Sbrian    strncpy(cx->cfg.script.hangup, argp, sizeof cx->cfg.script.hangup - 1);
152436285Sbrian    cx->cfg.script.hangup[sizeof cx->cfg.script.hangup - 1] = '\0';
152528679Sbrian    break;
152637210Sbrian
152736285Sbrian  case VAR_IDLETIMEOUT:
152836285Sbrian    if (arg->argc > arg->argn+1)
152936285Sbrian      err = "Too many idle timeout values\n";
153036285Sbrian    else if (arg->argc == arg->argn+1)
153136285Sbrian      bundle_SetIdleTimer(arg->bundle, atoi(argp));
153236285Sbrian    if (err)
153336285Sbrian      log_Printf(LogWARN, err);
153429549Sbrian    break;
153537210Sbrian
153636285Sbrian  case VAR_LQRPERIOD:
153737210Sbrian    long_val = atol(argp);
153837210Sbrian    if (long_val < MIN_LQRPERIOD) {
153937210Sbrian      log_Printf(LogWARN, "%ld: Invalid lqr period - min %d\n",
154037210Sbrian                 long_val, MIN_LQRPERIOD);
154137210Sbrian      return 1;
154236285Sbrian    } else
154337210Sbrian      l->lcp.cfg.lqrperiod = long_val;
154436285Sbrian    break;
154537210Sbrian
154636285Sbrian  case VAR_LCPRETRY:
154737210Sbrian    long_val = atol(argp);
154837210Sbrian    if (long_val < MIN_FSMRETRY) {
154937210Sbrian      log_Printf(LogWARN, "%ld: Invalid LCP FSM retry period - min %d\n",
155037210Sbrian                 long_val, MIN_FSMRETRY);
155137210Sbrian      return 1;
155236285Sbrian    } else
155337210Sbrian      cx->physical->link.lcp.cfg.fsmretry = long_val;
155436285Sbrian    break;
155537210Sbrian
155636285Sbrian  case VAR_CHAPRETRY:
155737210Sbrian    long_val = atol(argp);
155837210Sbrian    if (long_val < MIN_FSMRETRY) {
155937210Sbrian      log_Printf(LogWARN, "%ld: Invalid CHAP FSM retry period - min %d\n",
156037210Sbrian                 long_val, MIN_FSMRETRY);
156137210Sbrian      return 1;
156236285Sbrian    } else
156337210Sbrian      cx->chap.auth.cfg.fsmretry = long_val;
156436285Sbrian    break;
156537210Sbrian
156636285Sbrian  case VAR_PAPRETRY:
156737210Sbrian    long_val = atol(argp);
156837210Sbrian    if (long_val < MIN_FSMRETRY) {
156937210Sbrian      log_Printf(LogWARN, "%ld: Invalid PAP FSM retry period - min %d\n",
157037210Sbrian                 long_val, MIN_FSMRETRY);
157137210Sbrian      return 1;
157236285Sbrian    } else
157337210Sbrian      cx->pap.cfg.fsmretry = long_val;
157436285Sbrian    break;
157537210Sbrian
157636285Sbrian  case VAR_CCPRETRY:
157737210Sbrian    long_val = atol(argp);
157837210Sbrian    if (long_val < MIN_FSMRETRY) {
157937210Sbrian      log_Printf(LogWARN, "%ld: Invalid CCP FSM retry period - min %d\n",
158037210Sbrian                 long_val, MIN_FSMRETRY);
158137210Sbrian      return 1;
158236285Sbrian    } else
158337210Sbrian      l->ccp.cfg.fsmretry = long_val;
158436285Sbrian    break;
158537210Sbrian
158636285Sbrian  case VAR_IPCPRETRY:
158737210Sbrian    long_val = atol(argp);
158837210Sbrian    if (long_val < MIN_FSMRETRY) {
158937210Sbrian      log_Printf(LogWARN, "%ld: Invalid IPCP FSM retry period - min %d\n",
159037210Sbrian                 long_val, MIN_FSMRETRY);
159137210Sbrian      return 1;
159236285Sbrian    } else
159337210Sbrian      arg->bundle->ncp.ipcp.cfg.fsmretry = long_val;
159436285Sbrian    break;
159537210Sbrian
159636285Sbrian  case VAR_NBNS:
159736285Sbrian  case VAR_DNS:
159836285Sbrian    if (param == VAR_DNS)
159936285Sbrian      addr = arg->bundle->ncp.ipcp.cfg.ns.dns;
160036285Sbrian    else
160136285Sbrian      addr = arg->bundle->ncp.ipcp.cfg.ns.nbns;
160236285Sbrian
160336285Sbrian    addr[0].s_addr = addr[1].s_addr = INADDR_ANY;
160436285Sbrian
160536285Sbrian    if (arg->argc > arg->argn) {
160636285Sbrian      ParseAddr(&arg->bundle->ncp.ipcp, 1, arg->argv + arg->argn,
160736285Sbrian                addr, &dummyaddr, &dummyint);
160836285Sbrian      if (arg->argc > arg->argn+1)
160936285Sbrian        ParseAddr(&arg->bundle->ncp.ipcp, 1, arg->argv + arg->argn + 1,
161036285Sbrian                  addr + 1, &dummyaddr, &dummyint);
161136285Sbrian
161236285Sbrian      if (addr[1].s_addr == INADDR_ANY)
161336285Sbrian        addr[1].s_addr = addr[0].s_addr;
161436285Sbrian      if (addr[0].s_addr == INADDR_ANY)
161536285Sbrian        addr[0].s_addr = addr[1].s_addr;
161636285Sbrian    }
161736285Sbrian    break;
161838174Sbrian
161938174Sbrian  case VAR_CALLBACK:
162038174Sbrian    cx->cfg.callback.opmask = 0;
162138174Sbrian    for (dummyint = arg->argn; dummyint < arg->argc; dummyint++) {
162238174Sbrian      if (!strcasecmp(arg->argv[dummyint], "auth"))
162338174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_AUTH);
162438174Sbrian      else if (!strcasecmp(arg->argv[dummyint], "cbcp"))
162538174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_CBCP);
162638174Sbrian      else if (!strcasecmp(arg->argv[dummyint], "e.164")) {
162738174Sbrian        if (dummyint == arg->argc - 1)
162838174Sbrian          log_Printf(LogWARN, "No E.164 arg (E.164 ignored) !\n");
162938174Sbrian        else {
163038174Sbrian          cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_E164);
163138174Sbrian          strncpy(cx->cfg.callback.msg, arg->argv[++dummyint],
163238174Sbrian                  sizeof cx->cfg.callback.msg - 1);
163338174Sbrian          cx->cfg.callback.msg[sizeof cx->cfg.callback.msg - 1] = '\0';
163438174Sbrian        }
163538174Sbrian      } else if (!strcasecmp(arg->argv[dummyint], "none"))
163638174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_NONE);
163738174Sbrian      else
163838174Sbrian        return -1;
163938174Sbrian    }
164038174Sbrian    if (cx->cfg.callback.opmask == CALLBACK_BIT(CALLBACK_NONE))
164138174Sbrian      cx->cfg.callback.opmask = 0;
164238174Sbrian    break;
164338174Sbrian
164438174Sbrian  case VAR_CBCP:
164538174Sbrian    cx->cfg.cbcp.delay = 0;
164638174Sbrian    *cx->cfg.cbcp.phone = '\0';
164738174Sbrian    cx->cfg.cbcp.fsmretry = DEF_FSMRETRY;
164838174Sbrian    if (arg->argc > arg->argn) {
164938174Sbrian      strncpy(cx->cfg.cbcp.phone, arg->argv[arg->argn],
165038174Sbrian              sizeof cx->cfg.cbcp.phone - 1);
165138174Sbrian      cx->cfg.cbcp.phone[sizeof cx->cfg.cbcp.phone - 1] = '\0';
165238174Sbrian      if (arg->argc > arg->argn + 1) {
165338174Sbrian        cx->cfg.cbcp.delay = atoi(arg->argv[arg->argn + 1]);
165438174Sbrian        if (arg->argc > arg->argn + 2) {
165538174Sbrian          long_val = atol(arg->argv[arg->argn + 2]);
165638174Sbrian          if (long_val < MIN_FSMRETRY)
165738174Sbrian            log_Printf(LogWARN, "%ld: Invalid CBCP FSM retry period - min %d\n",
165838174Sbrian                       long_val, MIN_FSMRETRY);
165938174Sbrian          else
166038174Sbrian            cx->cfg.cbcp.fsmretry = long_val;
166138174Sbrian        }
166238174Sbrian      }
166338174Sbrian    }
166438174Sbrian    break;
166538544Sbrian
166638544Sbrian  case VAR_CHOKED:
166738544Sbrian    arg->bundle->cfg.choked.timeout = atoi(argp);
166838544Sbrian    if (arg->bundle->cfg.choked.timeout <= 0)
166938544Sbrian      arg->bundle->cfg.choked.timeout = CHOKED_TIMEOUT;
167038544Sbrian    break;
167140665Sbrian
167240665Sbrian  case VAR_SENDPIPE:
167340665Sbrian    long_val = atol(argp);
167440665Sbrian    arg->bundle->ncp.ipcp.cfg.sendpipe = long_val;
167540665Sbrian    break;
167640665Sbrian
167740665Sbrian  case VAR_RECVPIPE:
167840665Sbrian    long_val = atol(argp);
167940665Sbrian    arg->bundle->ncp.ipcp.cfg.recvpipe = long_val;
168040665Sbrian    break;
16816059Samurai  }
168236285Sbrian
168336285Sbrian  return err ? 1 : 0;
16846059Samurai}
16856059Samurai
168628679Sbrianstatic int
168731343SbrianSetCtsRts(struct cmdargs const *arg)
168820812Sjkh{
168936285Sbrian  if (arg->argc == arg->argn+1) {
169036285Sbrian    if (strcmp(arg->argv[arg->argn], "on") == 0)
169136285Sbrian      physical_SetRtsCts(arg->cx->physical, 1);
169236285Sbrian    else if (strcmp(arg->argv[arg->argn], "off") == 0)
169336285Sbrian      physical_SetRtsCts(arg->cx->physical, 0);
169420812Sjkh    else
169526516Sbrian      return -1;
169626516Sbrian    return 0;
169720812Sjkh  }
169826516Sbrian  return -1;
169920812Sjkh}
170020812Sjkh
170130715Sbrianstatic struct cmdtab const SetCommands[] = {
170236285Sbrian  {"accmap", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
170336285Sbrian  "accmap value", "set accmap hex-value", (const void *)VAR_ACCMAP},
170428679Sbrian  {"authkey", "key", SetVariable, LOCAL_AUTH,
170536285Sbrian  "authentication key", "set authkey|key key", (const void *)VAR_AUTHKEY},
170628679Sbrian  {"authname", NULL, SetVariable, LOCAL_AUTH,
170736285Sbrian  "authentication name", "set authname name", (const void *)VAR_AUTHNAME},
170836285Sbrian  {"autoload", NULL, SetVariable, LOCAL_AUTH,
170936285Sbrian  "auto link [de]activation", "set autoload maxtime maxload mintime minload",
171036285Sbrian  (const void *)VAR_AUTOLOAD},
171138174Sbrian  {"callback", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
171238174Sbrian  "callback control", "set callback [none|auth|cbcp|"
171338174Sbrian  "E.164 *|number[,number]...]...", (const void *)VAR_CALLBACK},
171438174Sbrian  {"cbcp", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
171538174Sbrian  "CBCP control", "set cbcp [*|phone[,phone...] [delay [timeout]]]",
171638174Sbrian  (const void *)VAR_CBCP},
171736285Sbrian  {"ccpretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
171836285Sbrian  "FSM retry period", "set ccpretry value", (const void *)VAR_CCPRETRY},
171936285Sbrian  {"chapretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
172036285Sbrian  "CHAP retry period", "set chapretry value", (const void *)VAR_CHAPRETRY},
172138544Sbrian  {"choked", NULL, SetVariable, LOCAL_AUTH,
172238544Sbrian  "choked timeout", "set choked [secs]", (const void *)VAR_CHOKED},
172336285Sbrian  {"ctsrts", "crtscts", SetCtsRts, LOCAL_AUTH | LOCAL_CX,
172436285Sbrian  "Use hardware flow control", "set ctsrts [on|off]"},
172536285Sbrian  {"deflate", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
172636285Sbrian  "deflate window sizes", "set deflate out-winsize in-winsize",
172736285Sbrian  (const void *) VAR_WINSIZE},
172836285Sbrian  {"device", "line", SetVariable, LOCAL_AUTH | LOCAL_CX,
172936285Sbrian  "modem device name", "set device|line device-name[,device-name]",
173036285Sbrian  (const void *) VAR_DEVICE},
173136285Sbrian  {"dial", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
173236285Sbrian  "dialing script", "set dial chat-script", (const void *) VAR_DIAL},
173336285Sbrian  {"dns", NULL, SetVariable, LOCAL_AUTH, "Domain Name Server",
173436285Sbrian  "set dns pri-addr [sec-addr]", (const void *)VAR_DNS},
173536285Sbrian  {"enddisc", NULL, mp_SetEnddisc, LOCAL_AUTH,
173636285Sbrian  "Endpoint Discriminator", "set enddisc [IP|magic|label|psn value]"},
173736285Sbrian  {"escape", NULL, SetEscape, LOCAL_AUTH | LOCAL_CX,
173836285Sbrian  "escape characters", "set escape hex-digit ..."},
173936285Sbrian  {"filter", NULL, filter_Set, LOCAL_AUTH,
174036285Sbrian  "packet filters", "set filter alive|dial|in|out rule-no permit|deny "
174136285Sbrian  "[src_addr[/width]] [dst_addr[/width]] [tcp|udp|icmp [src [lt|eq|gt port]] "
174236285Sbrian  "[dst [lt|eq|gt port]] [estab] [syn] [finrst]]"},
174336285Sbrian  {"hangup", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
174436285Sbrian  "hangup script", "set hangup chat-script", (const void *) VAR_HANGUP},
174536285Sbrian  {"ifaddr", NULL, SetInterfaceAddr, LOCAL_AUTH, "destination address",
174631343Sbrian  "set ifaddr [src-addr [dst-addr [netmask [trg-addr]]]]"},
174736285Sbrian  {"ipcpretry", NULL, SetVariable, LOCAL_AUTH,
174836285Sbrian  "FSM retry period", "set ipcpretry value", (const void *)VAR_IPCPRETRY},
174936285Sbrian  {"lcpretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
175036285Sbrian  "FSM retry period", "set lcpretry value", (const void *)VAR_LCPRETRY},
175136712Sbrian  {"log", NULL, log_SetLevel, LOCAL_AUTH, "log level",
175238622Sbrian  "set log [local] [+|-]async|cbcp|ccp|chat|command|connect|debug|hdlc|id0|"
175338622Sbrian  "ipcp|lcp|lqm|phase|tcp/ip|timer|tun..."},
175436285Sbrian  {"login", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
175536285Sbrian  "login script", "set login chat-script", (const void *) VAR_LOGIN},
175636285Sbrian  {"lqrperiod", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
175736285Sbrian  "LQR period", "set lqrperiod value", (const void *)VAR_LQRPERIOD},
175836285Sbrian  {"mode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "mode value",
175936285Sbrian  "set mode interactive|auto|ddial|background", (const void *)VAR_MODE},
176036285Sbrian  {"mrru", NULL, SetVariable, LOCAL_AUTH, "MRRU value",
176136285Sbrian  "set mrru value", (const void *)VAR_MRRU},
176236285Sbrian  {"mru", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
176336285Sbrian  "MRU value", "set mru value", (const void *)VAR_MRU},
176436285Sbrian  {"mtu", NULL, SetVariable, LOCAL_AUTH,
176536285Sbrian  "interface MTU value", "set mtu value", (const void *)VAR_MTU},
176636285Sbrian  {"nbns", NULL, SetVariable, LOCAL_AUTH, "NetBIOS Name Server",
176736285Sbrian  "set nbns pri-addr [sec-addr]", (const void *)VAR_NBNS},
176836285Sbrian  {"openmode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "open mode",
176936285Sbrian  "set openmode active|passive [secs]", (const void *)VAR_OPENMODE},
177036285Sbrian  {"papretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
177136285Sbrian  "PAP retry period", "set papretry value", (const void *)VAR_PAPRETRY},
177236285Sbrian  {"parity", NULL, SetModemParity, LOCAL_AUTH | LOCAL_CX,
177336285Sbrian  "modem parity", "set parity [odd|even|none]"},
177436285Sbrian  {"phone", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "telephone number(s)",
177536285Sbrian  "set phone phone1[:phone2[...]]", (const void *)VAR_PHONE},
177636285Sbrian  {"reconnect", NULL, datalink_SetReconnect, LOCAL_AUTH | LOCAL_CX,
177736285Sbrian  "Reconnect timeout", "set reconnect value ntries"},
177840665Sbrian  {"recvpipe", NULL, SetVariable, LOCAL_AUTH,
177940665Sbrian  "RECVPIPE value", "set recvpipe value", (const void *)VAR_RECVPIPE},
178036285Sbrian  {"redial", NULL, datalink_SetRedial, LOCAL_AUTH | LOCAL_CX,
178136285Sbrian  "Redial timeout", "set redial value|random[.value|random] [attempts]"},
178240665Sbrian  {"sendpipe", NULL, SetVariable, LOCAL_AUTH,
178340665Sbrian  "SENDPIPE value", "set sendpipe value", (const void *)VAR_SENDPIPE},
178428679Sbrian  {"server", "socket", SetServer, LOCAL_AUTH,
178536774Sbrian  "server port", "set server|socket TcpPort|LocalName|none password [mask]"},
178636285Sbrian  {"speed", NULL, SetModemSpeed, LOCAL_AUTH | LOCAL_CX,
178736285Sbrian  "modem speed", "set speed value"},
178836285Sbrian  {"stopped", NULL, SetStoppedTimeout, LOCAL_AUTH | LOCAL_CX,
178936285Sbrian  "STOPPED timeouts", "set stopped [LCPseconds [CCPseconds]]"},
179036285Sbrian  {"timeout", NULL, SetVariable, LOCAL_AUTH, "Idle timeout",
179136285Sbrian  "set timeout idletime", (const void *)VAR_IDLETIMEOUT},
179236285Sbrian  {"vj", NULL, ipcp_vjset, LOCAL_AUTH,
179336285Sbrian  "vj values", "set vj slots|slotcomp [value]"},
179436285Sbrian  {"weight", NULL, mp_SetDatalinkWeight, LOCAL_AUTH | LOCAL_CX,
179536285Sbrian  "datalink weighting", "set weight n"},
179628679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
179731343Sbrian  "Display this message", "set help|? [command]", SetCommands},
179828679Sbrian  {NULL, NULL, NULL},
17996059Samurai};
18006059Samurai
18016059Samuraistatic int
180231343SbrianSetCommand(struct cmdargs const *arg)
18036059Samurai{
180436285Sbrian  if (arg->argc > arg->argn)
180536285Sbrian    FindExec(arg->bundle, SetCommands, arg->argc, arg->argn, arg->argv,
180636285Sbrian             arg->prompt, arg->cx);
180736285Sbrian  else if (arg->prompt)
180836285Sbrian    prompt_Printf(arg->prompt, "Use `set ?' to get a list or `set ? <var>' for"
180926516Sbrian	    " syntax help.\n");
18106059Samurai  else
181136285Sbrian    log_Printf(LogWARN, "set command must have arguments\n");
181226516Sbrian
181326516Sbrian  return 0;
18146059Samurai}
18156059Samurai
18166059Samuraistatic int
181731343SbrianAddCommand(struct cmdargs const *arg)
18186059Samurai{
18196059Samurai  struct in_addr dest, gateway, netmask;
182036285Sbrian  int gw, addrs;
18216059Samurai
182236285Sbrian  if (arg->argc != arg->argn+3 && arg->argc != arg->argn+2)
182331598Sbrian    return -1;
182431598Sbrian
182536285Sbrian  addrs = 0;
182636285Sbrian  if (arg->argc == arg->argn+2) {
182736285Sbrian    if (!strcasecmp(arg->argv[arg->argn], "default"))
182836285Sbrian      dest.s_addr = netmask.s_addr = INADDR_ANY;
182931598Sbrian    else {
183036285Sbrian      int width;
183136285Sbrian
183236285Sbrian      if (!ParseAddr(&arg->bundle->ncp.ipcp, 1, arg->argv + arg->argn,
183336285Sbrian	             &dest, &netmask, &width))
183436285Sbrian        return -1;
183536285Sbrian      if (!strncasecmp(arg->argv[arg->argn], "MYADDR", 6))
183636285Sbrian        addrs = ROUTE_DSTMYADDR;
183736285Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "HISADDR", 7))
183836285Sbrian        addrs = ROUTE_DSTHISADDR;
183931598Sbrian    }
184036285Sbrian    gw = 1;
184134536Sbrian  } else {
184236285Sbrian    if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
184336285Sbrian      addrs = ROUTE_DSTMYADDR;
184436285Sbrian      dest = arg->bundle->ncp.ipcp.my_ip;
184536285Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
184636285Sbrian      addrs = ROUTE_DSTHISADDR;
184736285Sbrian      dest = arg->bundle->ncp.ipcp.peer_ip;
184836285Sbrian    } else
184936285Sbrian      dest = GetIpAddr(arg->argv[arg->argn]);
185036285Sbrian    netmask = GetIpAddr(arg->argv[arg->argn+1]);
185131598Sbrian    gw = 2;
18526059Samurai  }
185336285Sbrian
185436285Sbrian  if (strcasecmp(arg->argv[arg->argn+gw], "HISADDR") == 0) {
185536285Sbrian    gateway = arg->bundle->ncp.ipcp.peer_ip;
185636285Sbrian    addrs |= ROUTE_GWHISADDR;
185740561Sbrian  } else
185836285Sbrian    gateway = GetIpAddr(arg->argv[arg->argn+gw]);
185936285Sbrian
186036285Sbrian  if (bundle_SetRoute(arg->bundle, RTM_ADD, dest, gateway, netmask,
186137927Sbrian                  arg->cmd->args ? 1 : 0, (addrs & ROUTE_GWHISADDR) ? 1 : 0))
186236285Sbrian    route_Add(&arg->bundle->ncp.ipcp.route, addrs, dest, netmask, gateway);
186336285Sbrian
186431598Sbrian  return 0;
18656059Samurai}
18666059Samurai
18676059Samuraistatic int
186831343SbrianDeleteCommand(struct cmdargs const *arg)
18696059Samurai{
187031598Sbrian  struct in_addr dest, none;
187136285Sbrian  int addrs;
18726059Samurai
187336285Sbrian  if (arg->argc == arg->argn+1) {
187436285Sbrian    if(strcasecmp(arg->argv[arg->argn], "all") == 0) {
187536285Sbrian      route_IfDelete(arg->bundle, 0);
187636285Sbrian      route_DeleteAll(&arg->bundle->ncp.ipcp.route);
187736285Sbrian    } else {
187836285Sbrian      addrs = 0;
187936285Sbrian      if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
188036285Sbrian        dest = arg->bundle->ncp.ipcp.my_ip;
188136285Sbrian        addrs = ROUTE_DSTMYADDR;
188236285Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
188336285Sbrian        dest = arg->bundle->ncp.ipcp.peer_ip;
188436285Sbrian        addrs = ROUTE_DSTHISADDR;
188536285Sbrian      } else {
188636285Sbrian        if (strcasecmp(arg->argv[arg->argn], "default") == 0)
188736285Sbrian          dest.s_addr = INADDR_ANY;
188836285Sbrian        else
188936285Sbrian          dest = GetIpAddr(arg->argv[arg->argn]);
189036285Sbrian        addrs = ROUTE_STATIC;
189136285Sbrian      }
189231598Sbrian      none.s_addr = INADDR_ANY;
189336285Sbrian      bundle_SetRoute(arg->bundle, RTM_DELETE, dest, none, none,
189437927Sbrian                      arg->cmd->args ? 1 : 0, 0);
189536285Sbrian      route_Delete(&arg->bundle->ncp.ipcp.route, addrs, dest);
189631598Sbrian    }
189734536Sbrian  } else
189826516Sbrian    return -1;
189926516Sbrian
190026516Sbrian  return 0;
19016059Samurai}
19026059Samurai
190331343Sbrian#ifndef NOALIAS
190426031Sbrianstatic int
190531343SbrianAliasEnable(struct cmdargs const *arg)
190626031Sbrian{
190736285Sbrian  if (arg->argc == arg->argn+1) {
190836285Sbrian    if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
190937191Sbrian      arg->bundle->AliasEnabled = 1;
191037191Sbrian      return 0;
191136285Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "no") == 0) {
191237191Sbrian      arg->bundle->AliasEnabled = 0;
191340561Sbrian      arg->bundle->cfg.opt &= ~OPT_IFACEALIAS;
191440561Sbrian      /* Don't iface_Clear() - there may be manually configured addresses */
191526516Sbrian      return 0;
191626142Sbrian    }
191735449Sbrian  }
191836285Sbrian
191926516Sbrian  return -1;
192026031Sbrian}
192126031Sbrian
192226031Sbrian
192326031Sbrianstatic int
192431343SbrianAliasOption(struct cmdargs const *arg)
192526031Sbrian{
192638559Sbrian  long param = (long)arg->cmd->args;
192738559Sbrian
192836285Sbrian  if (arg->argc == arg->argn+1) {
192936285Sbrian    if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
193037191Sbrian      if (arg->bundle->AliasEnabled) {
193137191Sbrian	PacketAliasSetMode(param, param);
193228679Sbrian	return 0;
193328679Sbrian      }
193436285Sbrian      log_Printf(LogWARN, "alias not enabled\n");
193536285Sbrian    } else if (strcmp(arg->argv[arg->argn], "no") == 0) {
193637191Sbrian      if (arg->bundle->AliasEnabled) {
193737191Sbrian	PacketAliasSetMode(0, param);
193828679Sbrian	return 0;
193928679Sbrian      }
194036285Sbrian      log_Printf(LogWARN, "alias not enabled\n");
194128679Sbrian    }
194235449Sbrian  }
194328679Sbrian  return -1;
194426031Sbrian}
194531343Sbrian#endif /* #ifndef NOALIAS */
194631121Sbrian
194731121Sbrianstatic int
194836285SbrianLinkCommand(struct cmdargs const *arg)
194936285Sbrian{
195036285Sbrian  if (arg->argc > arg->argn+1) {
195136285Sbrian    char namelist[LINE_LEN];
195236285Sbrian    struct datalink *cx;
195336285Sbrian    char *name;
195436285Sbrian    int result = 0;
195536285Sbrian
195636285Sbrian    if (!strcmp(arg->argv[arg->argn], "*")) {
195736285Sbrian      struct datalink *dl;
195836285Sbrian
195936285Sbrian      cx = arg->bundle->links;
196036285Sbrian      while (cx) {
196136285Sbrian        /* Watch it, the command could be a ``remove'' */
196236285Sbrian        dl = cx->next;
196336285Sbrian        FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
196436285Sbrian                 arg->prompt, cx);
196536285Sbrian        for (cx = arg->bundle->links; cx; cx = cx->next)
196636285Sbrian          if (cx == dl)
196736285Sbrian            break;		/* Pointer's still valid ! */
196836285Sbrian      }
196936285Sbrian    } else {
197036285Sbrian      strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
197136285Sbrian      namelist[sizeof namelist - 1] = '\0';
197236285Sbrian      for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
197336285Sbrian        if (!bundle2datalink(arg->bundle, name)) {
197436285Sbrian          log_Printf(LogWARN, "link: %s: Invalid link name\n", name);
197536285Sbrian          return 1;
197636285Sbrian        }
197736285Sbrian
197836285Sbrian      strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
197936285Sbrian      namelist[sizeof namelist - 1] = '\0';
198036285Sbrian      for(name = strtok(namelist, ", "); name; name = strtok(NULL,", ")) {
198136285Sbrian        cx = bundle2datalink(arg->bundle, name);
198236285Sbrian        if (cx)
198336285Sbrian          FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
198436285Sbrian                   arg->prompt, cx);
198536285Sbrian        else {
198636285Sbrian          log_Printf(LogWARN, "link: %s: Invalidated link name !\n", name);
198736285Sbrian          result++;
198836285Sbrian        }
198936285Sbrian      }
199036285Sbrian    }
199136285Sbrian    return result;
199236285Sbrian  }
199336285Sbrian
199436285Sbrian  log_Printf(LogWARN, "Usage: %s\n", arg->cmd->syntax);
199536285Sbrian  return 2;
199636285Sbrian}
199736285Sbrian
199836285Sbrianstruct link *
199936285Sbriancommand_ChooseLink(struct cmdargs const *arg)
200036285Sbrian{
200136285Sbrian  if (arg->cx)
200236285Sbrian    return &arg->cx->physical->link;
200337210Sbrian  else if (!arg->bundle->ncp.mp.cfg.mrru) {
200436285Sbrian    struct datalink *dl = bundle2datalink(arg->bundle, NULL);
200537210Sbrian    if (dl)
200637210Sbrian      return &dl->physical->link;
200736285Sbrian  }
200837210Sbrian  return &arg->bundle->ncp.mp.link;
200936285Sbrian}
201036285Sbrian
201136285Sbrianstatic const char *
201236285Sbrianident_cmd(const char *cmd, unsigned *keep, unsigned *add)
201336285Sbrian{
201436285Sbrian  const char *result;
201536285Sbrian
201636285Sbrian  switch (*cmd) {
201736285Sbrian    case 'A':
201836285Sbrian    case 'a':
201936285Sbrian      result = "accept";
202036285Sbrian      *keep = NEG_MYMASK;
202136285Sbrian      *add = NEG_ACCEPTED;
202236285Sbrian      break;
202336285Sbrian    case 'D':
202436285Sbrian    case 'd':
202536285Sbrian      switch (cmd[1]) {
202636285Sbrian        case 'E':
202736285Sbrian        case 'e':
202836285Sbrian          result = "deny";
202936285Sbrian          *keep = NEG_MYMASK;
203036285Sbrian          *add = 0;
203136285Sbrian          break;
203236285Sbrian        case 'I':
203336285Sbrian        case 'i':
203436285Sbrian          result = "disable";
203536285Sbrian          *keep = NEG_HISMASK;
203636285Sbrian          *add = 0;
203736285Sbrian          break;
203836285Sbrian        default:
203936285Sbrian          return NULL;
204036285Sbrian      }
204136285Sbrian      break;
204236285Sbrian    case 'E':
204336285Sbrian    case 'e':
204436285Sbrian      result = "enable";
204536285Sbrian      *keep = NEG_HISMASK;
204636285Sbrian      *add = NEG_ENABLED;
204736285Sbrian      break;
204836285Sbrian    default:
204936285Sbrian      return NULL;
205036285Sbrian  }
205136285Sbrian
205236285Sbrian  return result;
205336285Sbrian}
205436285Sbrian
205536285Sbrianstatic int
205636285SbrianOptSet(struct cmdargs const *arg)
205736285Sbrian{
205837574Sbrian  int bit = (int)(long)arg->cmd->args;
205936285Sbrian  const char *cmd;
206036285Sbrian  unsigned keep;			/* Keep these bits */
206136285Sbrian  unsigned add;				/* Add these bits */
206236285Sbrian
206336285Sbrian  if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL)
206436285Sbrian    return 1;
206536285Sbrian
206636285Sbrian  if (add)
206736285Sbrian    arg->bundle->cfg.opt |= bit;
206836285Sbrian  else
206936285Sbrian    arg->bundle->cfg.opt &= ~bit;
207036285Sbrian  return 0;
207136285Sbrian}
207236285Sbrian
207336285Sbrianstatic int
207440561SbrianIfaceAliasOptSet(struct cmdargs const *arg)
207540561Sbrian{
207640561Sbrian  unsigned save = arg->bundle->cfg.opt;
207740561Sbrian  int result = OptSet(arg);
207840561Sbrian
207940561Sbrian  if (result == 0)
208040561Sbrian    if (Enabled(arg->bundle, OPT_IFACEALIAS) && !arg->bundle->AliasEnabled) {
208140561Sbrian      arg->bundle->cfg.opt = save;
208240561Sbrian      log_Printf(LogWARN, "Cannot enable iface-alias without IP aliasing\n");
208340561Sbrian      result = 2;
208440561Sbrian    }
208540561Sbrian
208640561Sbrian  return result;
208740561Sbrian}
208840561Sbrian
208940561Sbrianstatic int
209036285SbrianNegotiateSet(struct cmdargs const *arg)
209136285Sbrian{
209237210Sbrian  long param = (long)arg->cmd->args;
209336285Sbrian  struct link *l = command_ChooseLink(arg);	/* LOCAL_CX_OPT uses this */
209436285Sbrian  struct datalink *cx = arg->cx;	/* LOCAL_CX uses this */
209536285Sbrian  const char *cmd;
209636285Sbrian  unsigned keep;			/* Keep these bits */
209736285Sbrian  unsigned add;				/* Add these bits */
209836285Sbrian
209936285Sbrian  if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL)
210036285Sbrian    return 1;
210136285Sbrian
210236285Sbrian  if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
210336285Sbrian    log_Printf(LogWARN, "%s %s: No context (use the `link' command)\n",
210436285Sbrian              cmd, arg->cmd->name);
210536285Sbrian    return 2;
210636285Sbrian  } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
210736285Sbrian    log_Printf(LogWARN, "%s %s: Redundant context (%s) ignored\n",
210836285Sbrian              cmd, arg->cmd->name, cx->name);
210936285Sbrian    cx = NULL;
211036285Sbrian  }
211136285Sbrian
211236285Sbrian  switch (param) {
211336285Sbrian    case NEG_ACFCOMP:
211436285Sbrian      cx->physical->link.lcp.cfg.acfcomp &= keep;
211536285Sbrian      cx->physical->link.lcp.cfg.acfcomp |= add;
211636285Sbrian      break;
211736285Sbrian    case NEG_CHAP:
211836285Sbrian      cx->physical->link.lcp.cfg.chap &= keep;
211936285Sbrian      cx->physical->link.lcp.cfg.chap |= add;
212036285Sbrian      break;
212136285Sbrian    case NEG_DEFLATE:
212236285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE] &= keep;
212336285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE] |= add;
212436285Sbrian      break;
212536285Sbrian    case NEG_DNS:
212636285Sbrian      arg->bundle->ncp.ipcp.cfg.ns.dns_neg &= keep;
212736285Sbrian      arg->bundle->ncp.ipcp.cfg.ns.dns_neg |= add;
212836285Sbrian      break;
212936285Sbrian    case NEG_LQR:
213036285Sbrian      cx->physical->link.lcp.cfg.lqr &= keep;
213136285Sbrian      cx->physical->link.lcp.cfg.lqr |= add;
213236285Sbrian      break;
213336285Sbrian    case NEG_PAP:
213436285Sbrian      cx->physical->link.lcp.cfg.pap &= keep;
213536285Sbrian      cx->physical->link.lcp.cfg.pap |= add;
213636285Sbrian      break;
213736285Sbrian    case NEG_PPPDDEFLATE:
213836285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE24] &= keep;
213936285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE24] |= add;
214036285Sbrian      break;
214136285Sbrian    case NEG_PRED1:
214236285Sbrian      l->ccp.cfg.neg[CCP_NEG_PRED1] &= keep;
214336285Sbrian      l->ccp.cfg.neg[CCP_NEG_PRED1] |= add;
214436285Sbrian      break;
214536285Sbrian    case NEG_PROTOCOMP:
214636285Sbrian      cx->physical->link.lcp.cfg.protocomp &= keep;
214736285Sbrian      cx->physical->link.lcp.cfg.protocomp |= add;
214836285Sbrian      break;
214936285Sbrian    case NEG_SHORTSEQ:
215040622Sbrian      switch (bundle_Phase(arg->bundle)) {
215140622Sbrian        case PHASE_DEAD:
215240622Sbrian          break;
215340622Sbrian        case PHASE_ESTABLISH:
215440622Sbrian          /* Make sure none of our links are DATALINK_LCP or greater */
215540622Sbrian          if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) {
215640622Sbrian            log_Printf(LogWARN, "shortseq: Only changable before"
215740622Sbrian                       " LCP negotiations\n");
215840622Sbrian            return 1;
215940622Sbrian          }
216040622Sbrian          break;
216140622Sbrian        default:
216240622Sbrian          log_Printf(LogWARN, "shortseq: Only changable at phase"
216340622Sbrian                     " DEAD/ESTABLISH\n");
216440622Sbrian          return 1;
216536285Sbrian      }
216640622Sbrian      arg->bundle->ncp.mp.cfg.shortseq &= keep;
216740622Sbrian      arg->bundle->ncp.mp.cfg.shortseq |= add;
216836285Sbrian      break;
216936285Sbrian    case NEG_VJCOMP:
217036285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.neg &= keep;
217136285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.neg |= add;
217236285Sbrian      break;
217336285Sbrian  }
217436285Sbrian
217536285Sbrian  return 0;
217636285Sbrian}
217736285Sbrian
217836285Sbrianstatic struct cmdtab const NegotiateCommands[] = {
217936285Sbrian  {"idcheck", NULL, OptSet, LOCAL_AUTH, "Check FSM reply ids",
218036285Sbrian  "disable|enable", (const void *)OPT_IDCHECK},
218136285Sbrian  {"loopback", NULL, OptSet, LOCAL_AUTH, "Loop packets for local iface",
218236285Sbrian  "disable|enable", (const void *)OPT_LOOPBACK},
218336285Sbrian  {"passwdauth", NULL, OptSet, LOCAL_AUTH, "Use passwd file",
218436285Sbrian  "disable|enable", (const void *)OPT_PASSWDAUTH},
218540665Sbrian  {"proxy", NULL, OptSet, LOCAL_AUTH, "Create a proxy ARP entry",
218636285Sbrian  "disable|enable", (const void *)OPT_PROXY},
218740665Sbrian  {"proxyall", NULL, OptSet, LOCAL_AUTH, "Proxy ARP for all remote hosts",
218840665Sbrian  "disable|enable", (const void *)OPT_PROXYALL},
218936285Sbrian  {"sroutes", NULL, OptSet, LOCAL_AUTH, "Use sticky routes",
219036285Sbrian  "disable|enable", (const void *)OPT_SROUTES},
219136285Sbrian  {"throughput", NULL, OptSet, LOCAL_AUTH, "Rolling throughput",
219236285Sbrian  "disable|enable", (const void *)OPT_THROUGHPUT},
219336285Sbrian  {"utmp", NULL, OptSet, LOCAL_AUTH, "Log connections in utmp",
219436285Sbrian  "disable|enable", (const void *)OPT_UTMP},
219540561Sbrian  {"iface-alias", NULL, IfaceAliasOptSet, LOCAL_AUTH,
219640561Sbrian   "maintain interface addresses", "disable|enable",
219740561Sbrian   (const void *)OPT_IFACEALIAS},
219836285Sbrian
219940665Sbrian#define OPT_MAX 9	/* accept/deny allowed below and not above */
220036285Sbrian
220136285Sbrian  {"acfcomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
220236285Sbrian  "Address & Control field compression", "accept|deny|disable|enable",
220336285Sbrian  (const void *)NEG_ACFCOMP},
220436285Sbrian  {"chap", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
220536285Sbrian  "Challenge Handshake Authentication Protocol", "accept|deny|disable|enable",
220636285Sbrian  (const void *)NEG_CHAP},
220736285Sbrian  {"deflate", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
220836285Sbrian  "Deflate compression", "accept|deny|disable|enable",
220936285Sbrian  (const void *)NEG_DEFLATE},
221036285Sbrian  {"deflate24", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
221136285Sbrian  "Deflate (type 24) compression", "accept|deny|disable|enable",
221236285Sbrian  (const void *)NEG_PPPDDEFLATE},
221336285Sbrian  {"dns", NULL, NegotiateSet, LOCAL_AUTH,
221436285Sbrian  "DNS specification", "accept|deny|disable|enable", (const void *)NEG_DNS},
221536285Sbrian  {"lqr", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
221636285Sbrian  "Link Quality Reports", "accept|deny|disable|enable",
221736285Sbrian  (const void *)NEG_LQR},
221836285Sbrian  {"pap", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
221936285Sbrian  "Password Authentication protocol", "accept|deny|disable|enable",
222036285Sbrian  (const void *)NEG_PAP},
222136285Sbrian  {"pred1", "predictor1", NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
222236285Sbrian  "Predictor 1 compression", "accept|deny|disable|enable",
222336285Sbrian  (const void *)NEG_PRED1},
222436285Sbrian  {"protocomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
222536285Sbrian  "Protocol field compression", "accept|deny|disable|enable",
222636285Sbrian  (const void *)NEG_PROTOCOMP},
222736285Sbrian  {"shortseq", NULL, NegotiateSet, LOCAL_AUTH,
222836285Sbrian  "MP Short Sequence Numbers", "accept|deny|disable|enable",
222936285Sbrian  (const void *)NEG_SHORTSEQ},
223036285Sbrian  {"vjcomp", NULL, NegotiateSet, LOCAL_AUTH,
223136285Sbrian  "Van Jacobson header compression", "accept|deny|disable|enable",
223236285Sbrian  (const void *)NEG_VJCOMP},
223336285Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
223436285Sbrian  "Display this message", "accept|deny|disable|enable help|? [value]",
223536285Sbrian  NegotiateCommands},
223636285Sbrian  {NULL, NULL, NULL},
223736285Sbrian};
223836285Sbrian
223936285Sbrianstatic int
224036285SbrianNegotiateCommand(struct cmdargs const *arg)
224136285Sbrian{
224236285Sbrian  if (arg->argc > arg->argn) {
224336285Sbrian    char const *argv[3];
224436285Sbrian    unsigned keep, add;
224536285Sbrian    int n;
224636285Sbrian
224736285Sbrian    if ((argv[0] = ident_cmd(arg->argv[arg->argn-1], &keep, &add)) == NULL)
224836285Sbrian      return -1;
224936285Sbrian    argv[2] = NULL;
225036285Sbrian
225136285Sbrian    for (n = arg->argn; n < arg->argc; n++) {
225236285Sbrian      argv[1] = arg->argv[n];
225336285Sbrian      FindExec(arg->bundle, NegotiateCommands + (keep == NEG_HISMASK ?
225436285Sbrian               0 : OPT_MAX), 2, 1, argv, arg->prompt, arg->cx);
225536285Sbrian    }
225636285Sbrian  } else if (arg->prompt)
225736285Sbrian    prompt_Printf(arg->prompt, "Use `%s ?' to get a list.\n",
225836285Sbrian	    arg->argv[arg->argn-1]);
225936285Sbrian  else
226036285Sbrian    log_Printf(LogWARN, "%s command must have arguments\n",
226136285Sbrian              arg->argv[arg->argn] );
226236285Sbrian
226336285Sbrian  return 0;
226436285Sbrian}
226536285Sbrian
226636285Sbrianconst char *
226736285Sbriancommand_ShowNegval(unsigned val)
226836285Sbrian{
226936285Sbrian  switch (val&3) {
227036285Sbrian    case 1: return "disabled & accepted";
227136285Sbrian    case 2: return "enabled & denied";
227236285Sbrian    case 3: return "enabled & accepted";
227336285Sbrian  }
227436285Sbrian  return "disabled & denied";
227536285Sbrian}
227636934Sbrian
227736934Sbrianstatic int
227836934SbrianClearCommand(struct cmdargs const *arg)
227936934Sbrian{
228036934Sbrian  struct pppThroughput *t;
228136934Sbrian  struct datalink *cx;
228236934Sbrian  int i, clear_type;
228336934Sbrian
228436934Sbrian  if (arg->argc < arg->argn + 1)
228536934Sbrian    return -1;
228636934Sbrian
228736934Sbrian  if (strcasecmp(arg->argv[arg->argn], "modem") == 0) {
228836934Sbrian    cx = arg->cx;
228936934Sbrian    if (!cx)
229036934Sbrian      cx = bundle2datalink(arg->bundle, NULL);
229136934Sbrian    if (!cx) {
229236934Sbrian      log_Printf(LogWARN, "A link must be specified for ``clear modem''\n");
229336934Sbrian      return 1;
229436934Sbrian    }
229536934Sbrian    t = &cx->physical->link.throughput;
229636934Sbrian  } else if (strcasecmp(arg->argv[arg->argn], "ipcp") == 0)
229736934Sbrian    t = &arg->bundle->ncp.ipcp.throughput;
229836934Sbrian  else
229936934Sbrian    return -1;
230036934Sbrian
230136934Sbrian  if (arg->argc > arg->argn + 1) {
230236934Sbrian    clear_type = 0;
230336934Sbrian    for (i = arg->argn + 1; i < arg->argc; i++)
230436934Sbrian      if (strcasecmp(arg->argv[i], "overall") == 0)
230536934Sbrian        clear_type |= THROUGHPUT_OVERALL;
230636934Sbrian      else if (strcasecmp(arg->argv[i], "current") == 0)
230736934Sbrian        clear_type |= THROUGHPUT_CURRENT;
230836934Sbrian      else if (strcasecmp(arg->argv[i], "peak") == 0)
230936934Sbrian        clear_type |= THROUGHPUT_PEAK;
231036934Sbrian      else
231136934Sbrian        return -1;
231236934Sbrian  } else
231336934Sbrian    clear_type = THROUGHPUT_ALL;
231436934Sbrian
231536934Sbrian  throughput_clear(t, clear_type, arg->prompt);
231636934Sbrian  return 0;
231736934Sbrian}
231840561Sbrian
231940561Sbrianstatic int
232040561SbrianRunListCommand(struct cmdargs const *arg)
232140561Sbrian{
232240561Sbrian  const char *cmd = arg->argc ? arg->argv[arg->argc - 1] : "???";
232340561Sbrian
232440561Sbrian  if (arg->argc > arg->argn)
232540561Sbrian    FindExec(arg->bundle, arg->cmd->args, arg->argc, arg->argn, arg->argv,
232640561Sbrian             arg->prompt, arg->cx);
232740561Sbrian  else if (arg->prompt)
232840561Sbrian    prompt_Printf(arg->prompt, "Use `%s help' to get a list or `%s help"
232940561Sbrian                  " <option>' for syntax help.\n", cmd, cmd);
233040561Sbrian  else
233140561Sbrian    log_Printf(LogWARN, "%s command must have arguments\n", cmd);
233240561Sbrian
233340561Sbrian  return 0;
233440561Sbrian}
233540561Sbrian
233640561Sbrianstatic int
233740561SbrianIfaceAddCommand(struct cmdargs const *arg)
233840561Sbrian{
233940561Sbrian  int bits, n, how;
234040561Sbrian  struct in_addr ifa, mask, brd;
234140561Sbrian
234240664Sbrian  if (arg->argc == arg->argn + 1) {
234340561Sbrian    if (!ParseAddr(NULL, 1, arg->argv + arg->argn, &ifa, NULL, NULL))
234440561Sbrian      return -1;
234540664Sbrian    mask.s_addr = brd.s_addr = INADDR_BROADCAST;
234640664Sbrian  } else {
234740664Sbrian    if (arg->argc == arg->argn + 2) {
234840664Sbrian      if (!ParseAddr(NULL, 1, arg->argv + arg->argn, &ifa, &mask, &bits))
234940664Sbrian        return -1;
235040664Sbrian      n = 1;
235140664Sbrian    } else if (arg->argc == arg->argn + 3) {
235240664Sbrian      if (!ParseAddr(NULL, 1, arg->argv + arg->argn, &ifa, NULL, NULL))
235340664Sbrian        return -1;
235440664Sbrian      if (!ParseAddr(NULL, 1, arg->argv + arg->argn + 1, &mask, NULL, NULL))
235540664Sbrian        return -1;
235640664Sbrian      n = 2;
235740664Sbrian    } else
235840561Sbrian      return -1;
235940561Sbrian
236040664Sbrian    if (!ParseAddr(NULL, 1, arg->argv + arg->argn + n, &brd, NULL, NULL))
236140664Sbrian      return -1;
236240664Sbrian  }
236340561Sbrian
236440561Sbrian  how = IFACE_ADD_LAST;
236540561Sbrian  if (arg->cmd->args)
236640561Sbrian    how |= IFACE_FORCE_ADD;
236740561Sbrian
236840561Sbrian  return !iface_inAdd(arg->bundle->iface, ifa, mask, brd, how);
236940561Sbrian}
237040561Sbrian
237140561Sbrianstatic int
237240561SbrianIfaceDeleteCommand(struct cmdargs const *arg)
237340561Sbrian{
237440561Sbrian  struct in_addr ifa;
237540561Sbrian  int ok;
237640561Sbrian
237740561Sbrian  if (arg->argc != arg->argn + 1)
237840561Sbrian    return -1;
237940561Sbrian
238040561Sbrian  if (!ParseAddr(NULL, 1, arg->argv + arg->argn, &ifa, NULL, NULL))
238140561Sbrian    return -1;
238240561Sbrian
238340561Sbrian  if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED &&
238440561Sbrian      arg->bundle->ncp.ipcp.my_ip.s_addr == ifa.s_addr) {
238540561Sbrian    log_Printf(LogWARN, "%s: Cannot remove active interface address\n",
238640561Sbrian               inet_ntoa(ifa));
238740561Sbrian    return 1;
238840561Sbrian  }
238940561Sbrian
239040561Sbrian  ok = iface_inDelete(arg->bundle->iface, ifa);
239140561Sbrian  if (!ok) {
239240561Sbrian    if (arg->cmd->args)
239340561Sbrian      ok = 1;
239440561Sbrian    else if (arg->prompt)
239540561Sbrian      prompt_Printf(arg->prompt, "%s: No such address\n", inet_ntoa(ifa));
239640561Sbrian    else
239740561Sbrian      log_Printf(LogWARN, "%s: No such address\n", inet_ntoa(ifa));
239840561Sbrian  }
239940561Sbrian
240040561Sbrian  return !ok;
240140561Sbrian}
240240561Sbrian
240340561Sbrianstatic int
240440561SbrianIfaceClearCommand(struct cmdargs const *arg)
240540561Sbrian{
240640561Sbrian  int how;
240740561Sbrian
240840561Sbrian  if (arg->argc != arg->argn)
240940561Sbrian    return -1;
241040561Sbrian
241140561Sbrian  how = arg->bundle->ncp.ipcp.fsm.state == ST_OPENED ?
241240561Sbrian        IFACE_CLEAR_ALIASES : IFACE_CLEAR_ALL;
241340561Sbrian  iface_Clear(arg->bundle->iface, how);
241440561Sbrian
241540561Sbrian  return 0;
241640561Sbrian}
2417