command.c revision 62778
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 *
2050479Speter * $FreeBSD: head/usr.sbin/ppp/command.c 62778 2000-07-07 14:22:08Z brian $
218857Srgrimes *
226059Samurai */
2343313Sbrian#include <sys/param.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>
3653298Sbrian#ifdef __OpenBSD__
3753298Sbrian#include <util.h>
3853298Sbrian#else
3953298Sbrian#include <libutil.h>
4053298Sbrian#endif
4130715Sbrian#include <paths.h>
4230715Sbrian#include <stdio.h>
4330715Sbrian#include <stdlib.h>
4430715Sbrian#include <string.h>
4530715Sbrian#include <sys/wait.h>
4630715Sbrian#include <termios.h>
4730715Sbrian#include <unistd.h>
4830715Sbrian
4950059Sbrian#ifndef NONAT
5058037Sbrian#ifdef LOCALNAT
5158037Sbrian#include "alias.h"
5258037Sbrian#else
5346086Sbrian#include <alias.h>
5439395Sbrian#endif
5539395Sbrian#endif
5658037Sbrian
5746686Sbrian#include "layer.h"
5837009Sbrian#include "defs.h"
5931343Sbrian#include "command.h"
6030715Sbrian#include "mbuf.h"
6130715Sbrian#include "log.h"
6230715Sbrian#include "timer.h"
636059Samurai#include "fsm.h"
646059Samurai#include "lcp.h"
6531690Sbrian#include "iplist.h"
6636285Sbrian#include "throughput.h"
6736285Sbrian#include "slcompress.h"
6838557Sbrian#include "lqr.h"
6938557Sbrian#include "hdlc.h"
706059Samurai#include "ipcp.h"
7150059Sbrian#ifndef NONAT
7251075Sbrian#include "nat_cmd.h"
7331343Sbrian#endif
7425630Sbrian#include "systems.h"
7536285Sbrian#include "filter.h"
7636285Sbrian#include "descriptor.h"
7730715Sbrian#include "main.h"
7830715Sbrian#include "route.h"
7930715Sbrian#include "ccp.h"
8031080Sbrian#include "auth.h"
8136285Sbrian#include "async.h"
8236285Sbrian#include "link.h"
8336285Sbrian#include "physical.h"
8436285Sbrian#include "mp.h"
8543313Sbrian#ifndef NORADIUS
8643313Sbrian#include "radius.h"
8743313Sbrian#endif
8836285Sbrian#include "bundle.h"
8936285Sbrian#include "server.h"
9036285Sbrian#include "prompt.h"
9136285Sbrian#include "chat.h"
9236285Sbrian#include "chap.h"
9338174Sbrian#include "cbcp.h"
9436285Sbrian#include "datalink.h"
9540561Sbrian#include "iface.h"
9653298Sbrian#include "id.h"
976059Samurai
9836285Sbrian/* ``set'' values */
9936285Sbrian#define	VAR_AUTHKEY	0
10036285Sbrian#define	VAR_DIAL	1
10136285Sbrian#define	VAR_LOGIN	2
10236285Sbrian#define	VAR_AUTHNAME	3
10336285Sbrian#define	VAR_AUTOLOAD	4
10436285Sbrian#define	VAR_WINSIZE	5
10536285Sbrian#define	VAR_DEVICE	6
10636285Sbrian#define	VAR_ACCMAP	7
10736285Sbrian#define	VAR_MRRU	8
10836285Sbrian#define	VAR_MRU		9
10936285Sbrian#define	VAR_MTU		10
11036285Sbrian#define	VAR_OPENMODE	11
11136285Sbrian#define	VAR_PHONE	12
11236285Sbrian#define	VAR_HANGUP	13
11336285Sbrian#define	VAR_IDLETIMEOUT	14
11436285Sbrian#define	VAR_LQRPERIOD	15
11536285Sbrian#define	VAR_LCPRETRY	16
11636285Sbrian#define	VAR_CHAPRETRY	17
11736285Sbrian#define	VAR_PAPRETRY	18
11836285Sbrian#define	VAR_CCPRETRY	19
11936285Sbrian#define	VAR_IPCPRETRY	20
12036285Sbrian#define	VAR_DNS		21
12136285Sbrian#define	VAR_NBNS	22
12236285Sbrian#define	VAR_MODE	23
12338174Sbrian#define	VAR_CALLBACK	24
12438174Sbrian#define	VAR_CBCP	25
12538544Sbrian#define	VAR_CHOKED	26
12640665Sbrian#define	VAR_SENDPIPE	27
12740665Sbrian#define	VAR_RECVPIPE	28
12843313Sbrian#define	VAR_RADIUS	29
12944073Sbrian#define	VAR_CD		30
13046686Sbrian#define	VAR_PARITY	31
13146686Sbrian#define VAR_CRTSCTS	32
13250867Sbrian#define VAR_URGENTPORTS	33
13352488Sbrian#define	VAR_LOGOUT	34
13461534Sbrian#define	VAR_IFQUEUE	35
1356059Samurai
13636285Sbrian/* ``accept|deny|disable|enable'' masks */
13736285Sbrian#define NEG_HISMASK (1)
13836285Sbrian#define NEG_MYMASK (2)
13936285Sbrian
14036285Sbrian/* ``accept|deny|disable|enable'' values */
14136285Sbrian#define NEG_ACFCOMP	40
14244106Sbrian#define NEG_CHAP05	41
14344106Sbrian#define NEG_CHAP80	42
14444106Sbrian#define NEG_CHAP80LM	43
14544106Sbrian#define NEG_DEFLATE	44
14647858Sbrian#define NEG_DNS		45
14747858Sbrian#define NEG_ENDDISC	46
14847858Sbrian#define NEG_LQR		47
14947858Sbrian#define NEG_PAP		48
15047858Sbrian#define NEG_PPPDDEFLATE	49
15147858Sbrian#define NEG_PRED1	50
15247858Sbrian#define NEG_PROTOCOMP	51
15347858Sbrian#define NEG_SHORTSEQ	52
15447858Sbrian#define NEG_VJCOMP	53
15536285Sbrian
15653970Sbrianconst char Version[] = "2.26";
15736285Sbrian
15836285Sbrianstatic int ShowCommand(struct cmdargs const *);
15936285Sbrianstatic int TerminalCommand(struct cmdargs const *);
16036285Sbrianstatic int QuitCommand(struct cmdargs const *);
16136285Sbrianstatic int OpenCommand(struct cmdargs const *);
16236285Sbrianstatic int CloseCommand(struct cmdargs const *);
16336285Sbrianstatic int DownCommand(struct cmdargs const *);
16436285Sbrianstatic int SetCommand(struct cmdargs const *);
16536285Sbrianstatic int LinkCommand(struct cmdargs const *);
16636285Sbrianstatic int AddCommand(struct cmdargs const *);
16736285Sbrianstatic int DeleteCommand(struct cmdargs const *);
16836285Sbrianstatic int NegotiateCommand(struct cmdargs const *);
16936934Sbrianstatic int ClearCommand(struct cmdargs const *);
17040561Sbrianstatic int RunListCommand(struct cmdargs const *);
17140561Sbrianstatic int IfaceAddCommand(struct cmdargs const *);
17240561Sbrianstatic int IfaceDeleteCommand(struct cmdargs const *);
17340561Sbrianstatic int IfaceClearCommand(struct cmdargs const *);
17440679Sbrianstatic int SetProcTitle(struct cmdargs const *);
17550059Sbrian#ifndef NONAT
17658867Sbrianstatic int NatEnable(struct cmdargs const *);
17758867Sbrianstatic int NatOption(struct cmdargs const *);
17831343Sbrian#endif
1796059Samurai
18036285Sbrianstatic const char *
18136285Sbrianshowcx(struct cmdtab const *cmd)
18236285Sbrian{
18336285Sbrian  if (cmd->lauth & LOCAL_CX)
18436285Sbrian    return "(c)";
18536285Sbrian  else if (cmd->lauth & LOCAL_CX_OPT)
18636285Sbrian    return "(o)";
18736285Sbrian
18836285Sbrian  return "";
18936285Sbrian}
19036285Sbrian
1916059Samuraistatic int
19231343SbrianHelpCommand(struct cmdargs const *arg)
1936059Samurai{
19428679Sbrian  struct cmdtab const *cmd;
19536285Sbrian  int n, cmax, dmax, cols, cxlen;
19636285Sbrian  const char *cx;
1976059Samurai
19836285Sbrian  if (!arg->prompt) {
19936285Sbrian    log_Printf(LogWARN, "help: Cannot help without a prompt\n");
20026516Sbrian    return 0;
20136285Sbrian  }
20226516Sbrian
20336285Sbrian  if (arg->argc > arg->argn) {
20436285Sbrian    for (cmd = arg->cmdtab; cmd->name || cmd->alias; cmd++)
20536285Sbrian      if ((cmd->lauth & arg->prompt->auth) &&
20636285Sbrian          ((cmd->name && !strcasecmp(cmd->name, arg->argv[arg->argn])) ||
20736285Sbrian           (cmd->alias && !strcasecmp(cmd->alias, arg->argv[arg->argn])))) {
20836285Sbrian	prompt_Printf(arg->prompt, "%s %s\n", cmd->syntax, showcx(cmd));
20928679Sbrian	return 0;
2106059Samurai      }
21126516Sbrian    return -1;
2126059Samurai  }
21336285Sbrian
21431372Sbrian  cmax = dmax = 0;
21536285Sbrian  for (cmd = arg->cmdtab; cmd->func; cmd++)
21636285Sbrian    if (cmd->name && (cmd->lauth & arg->prompt->auth)) {
21736285Sbrian      if ((n = strlen(cmd->name) + strlen(showcx(cmd))) > cmax)
21831372Sbrian        cmax = n;
21931372Sbrian      if ((n = strlen(cmd->helpmes)) > dmax)
22031372Sbrian        dmax = n;
22131372Sbrian    }
22231372Sbrian
22331372Sbrian  cols = 80 / (dmax + cmax + 3);
2246059Samurai  n = 0;
22536285Sbrian  prompt_Printf(arg->prompt, "(o) = Optional context,"
22636285Sbrian                " (c) = Context required\n");
22736285Sbrian  for (cmd = arg->cmdtab; cmd->func; cmd++)
22836285Sbrian    if (cmd->name && (cmd->lauth & arg->prompt->auth)) {
22936285Sbrian      cx = showcx(cmd);
23036285Sbrian      cxlen = cmax - strlen(cmd->name);
23140482Sbrian      if (n % cols != 0)
23240482Sbrian        prompt_Printf(arg->prompt, " ");
23340482Sbrian      prompt_Printf(arg->prompt, "%s%-*.*s: %-*.*s",
23436285Sbrian              cmd->name, cxlen, cxlen, cx, dmax, dmax, cmd->helpmes);
23531372Sbrian      if (++n % cols == 0)
23636285Sbrian        prompt_Printf(arg->prompt, "\n");
2376059Samurai    }
23831372Sbrian  if (n % cols != 0)
23936285Sbrian    prompt_Printf(arg->prompt, "\n");
24026516Sbrian
24126516Sbrian  return 0;
2426059Samurai}
2436059Samurai
24436285Sbrianstatic int
24536285SbrianCloneCommand(struct cmdargs const *arg)
2466059Samurai{
24736285Sbrian  char namelist[LINE_LEN];
24836285Sbrian  char *name;
24936285Sbrian  int f;
2506059Samurai
25136285Sbrian  if (arg->argc == arg->argn)
25236285Sbrian    return -1;
25336285Sbrian
25436285Sbrian  namelist[sizeof namelist - 1] = '\0';
25536285Sbrian  for (f = arg->argn; f < arg->argc; f++) {
25636285Sbrian    strncpy(namelist, arg->argv[f], sizeof namelist - 1);
25736285Sbrian    for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
25836285Sbrian      bundle_DatalinkClone(arg->bundle, arg->cx, name);
2596059Samurai  }
26036285Sbrian
26136285Sbrian  return 0;
2626059Samurai}
2636059Samurai
2646059Samuraistatic int
26536285SbrianRemoveCommand(struct cmdargs const *arg)
2666059Samurai{
26736285Sbrian  if (arg->argc != arg->argn)
26836285Sbrian    return -1;
26911336Samurai
27036285Sbrian  if (arg->cx->state != DATALINK_CLOSED) {
27136285Sbrian    log_Printf(LogWARN, "remove: Cannot delete links that aren't closed\n");
27236285Sbrian    return 2;
2736059Samurai  }
27426516Sbrian
27536285Sbrian  bundle_DatalinkRemove(arg->bundle, arg->cx);
27636285Sbrian  return 0;
27736285Sbrian}
27832711Sbrian
27936285Sbrianstatic int
28036285SbrianRenameCommand(struct cmdargs const *arg)
28136285Sbrian{
28236285Sbrian  if (arg->argc != arg->argn + 1)
28336285Sbrian    return -1;
28431121Sbrian
28536285Sbrian  if (bundle_RenameDatalink(arg->bundle, arg->cx, arg->argv[arg->argn]))
28636285Sbrian    return 0;
28736285Sbrian
28836285Sbrian  log_Printf(LogWARN, "%s -> %s: target name already exists\n",
28936285Sbrian             arg->cx->name, arg->argv[arg->argn]);
29036285Sbrian  return 1;
29136285Sbrian}
29236285Sbrian
29336285Sbrianint
29436285SbrianLoadCommand(struct cmdargs const *arg)
29536285Sbrian{
29640797Sbrian  const char *err;
29740797Sbrian  int n, mode;
29836285Sbrian
29940797Sbrian  mode = arg->bundle->phys_type.all;
30036285Sbrian
30140797Sbrian  if (arg->argn < arg->argc) {
30240797Sbrian    for (n = arg->argn; n < arg->argc; n++)
30340797Sbrian      if ((err = system_IsValid(arg->argv[n], arg->prompt, mode)) != NULL) {
30440797Sbrian        log_Printf(LogWARN, "%s: %s\n", arg->argv[n], err);
30540797Sbrian        return 1;
30640797Sbrian      }
30740797Sbrian
30840797Sbrian    for (n = arg->argn; n < arg->argc; n++) {
30940797Sbrian      bundle_SetLabel(arg->bundle, arg->argv[arg->argc - 1]);
31040797Sbrian      system_Select(arg->bundle, arg->argv[n], CONFFILE, arg->prompt, arg->cx);
31140797Sbrian    }
31240797Sbrian    bundle_SetLabel(arg->bundle, arg->argv[arg->argc - 1]);
31340797Sbrian  } else if ((err = system_IsValid("default", arg->prompt, mode)) != NULL) {
31440797Sbrian    log_Printf(LogWARN, "default: %s\n", err);
31536285Sbrian    return 1;
31636285Sbrian  } else {
31740797Sbrian    bundle_SetLabel(arg->bundle, "default");
31840797Sbrian    system_Select(arg->bundle, "default", CONFFILE, arg->prompt, arg->cx);
31940797Sbrian    bundle_SetLabel(arg->bundle, "default");
32036285Sbrian  }
32140797Sbrian
32226516Sbrian  return 0;
3236059Samurai}
3246059Samurai
32536285Sbrianint
32636285SbrianSaveCommand(struct cmdargs const *arg)
32736285Sbrian{
32836285Sbrian  log_Printf(LogWARN, "save command is not implemented (yet).\n");
32936285Sbrian  return 1;
33036285Sbrian}
33136285Sbrian
33210528Samuraistatic int
33336285SbrianDialCommand(struct cmdargs const *arg)
33428536Sbrian{
33536285Sbrian  int res;
33636285Sbrian
33736465Sbrian  if ((arg->cx && !(arg->cx->physical->type & (PHYS_INTERACTIVE|PHYS_AUTO)))
33836465Sbrian      || (!arg->cx &&
33936928Sbrian          (arg->bundle->phys_type.all & ~(PHYS_INTERACTIVE|PHYS_AUTO)))) {
34036285Sbrian    log_Printf(LogWARN, "Manual dial is only available for auto and"
34136285Sbrian              " interactive links\n");
34236285Sbrian    return 1;
34334536Sbrian  }
34436285Sbrian
34536285Sbrian  if (arg->argc > arg->argn && (res = LoadCommand(arg)) != 0)
34636285Sbrian    return res;
34736285Sbrian
34837993Sbrian  bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1);
34936285Sbrian
35036285Sbrian  return 0;
35128536Sbrian}
35228536Sbrian
35338628Sbrian#define isinword(ch) (isalnum(ch) || (ch) == '_')
35438628Sbrian
35538628Sbrianstatic char *
35638628Sbrianstrstrword(char *big, const char *little)
35738628Sbrian{
35838628Sbrian  /* Get the first occurance of the word ``little'' in ``big'' */
35938628Sbrian  char *pos;
36038628Sbrian  int len;
36138628Sbrian
36238628Sbrian  pos = big;
36338628Sbrian  len = strlen(little);
36438628Sbrian
36538628Sbrian  while ((pos = strstr(pos, little)) != NULL)
36647865Sbrian    if ((pos != big && isinword(pos[-1])) || isinword(pos[len]))
36747865Sbrian      pos++;
36847865Sbrian    else if (pos != big && pos[-1] == '\\')
36947865Sbrian      memmove(pos - 1, pos, strlen(pos) + 1);
37047865Sbrian    else
37138628Sbrian      break;
37238628Sbrian
37338628Sbrian  return pos;
37438628Sbrian}
37538628Sbrian
37638628Sbrianstatic char *
37738628Sbriansubst(char *tgt, const char *oldstr, const char *newstr)
37838628Sbrian{
37938628Sbrian  /* tgt is a malloc()d area... realloc() as necessary */
38038628Sbrian  char *word, *ntgt;
38138628Sbrian  int ltgt, loldstr, lnewstr, pos;
38238628Sbrian
38338628Sbrian  if ((word = strstrword(tgt, oldstr)) == NULL)
38438628Sbrian    return tgt;
38538628Sbrian
38638628Sbrian  ltgt = strlen(tgt) + 1;
38738628Sbrian  loldstr = strlen(oldstr);
38838628Sbrian  lnewstr = strlen(newstr);
38938628Sbrian  do {
39038628Sbrian    pos = word - tgt;
39138628Sbrian    if (loldstr > lnewstr)
39238628Sbrian      bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr);
39338628Sbrian    if (loldstr != lnewstr) {
39438628Sbrian      ntgt = realloc(tgt, ltgt += lnewstr - loldstr);
39538628Sbrian      if (ntgt == NULL)
39638628Sbrian        break;			/* Oh wonderful ! */
39738628Sbrian      word = ntgt + pos;
39838628Sbrian      tgt = ntgt;
39938628Sbrian    }
40038628Sbrian    if (lnewstr > loldstr)
40138628Sbrian      bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr);
40238628Sbrian    bcopy(newstr, word, lnewstr);
40338628Sbrian  } while ((word = strstrword(word, oldstr)));
40438628Sbrian
40538628Sbrian  return tgt;
40638628Sbrian}
40738628Sbrian
40843888Sbrianvoid
40943888Sbriancommand_Expand(char **nargv, int argc, char const *const *oargv,
41047849Sbrian               struct bundle *bundle, int inc0, pid_t pid)
41138628Sbrian{
41238628Sbrian  int arg;
41347849Sbrian  char pidstr[12];
41438628Sbrian
41541755Sbrian  if (inc0)
41641755Sbrian    arg = 0;		/* Start at arg 0 */
41741755Sbrian  else {
41841755Sbrian    nargv[0] = strdup(oargv[0]);
41941755Sbrian    arg = 1;
42041755Sbrian  }
42147849Sbrian  snprintf(pidstr, sizeof pidstr, "%d", (int)pid);
42241755Sbrian  for (; arg < argc; arg++) {
42338629Sbrian    nargv[arg] = strdup(oargv[arg]);
42438629Sbrian    nargv[arg] = subst(nargv[arg], "HISADDR",
42538628Sbrian                       inet_ntoa(bundle->ncp.ipcp.peer_ip));
42638629Sbrian    nargv[arg] = subst(nargv[arg], "AUTHNAME", bundle->cfg.auth.name);
42740561Sbrian    nargv[arg] = subst(nargv[arg], "INTERFACE", bundle->iface->name);
42838628Sbrian    nargv[arg] = subst(nargv[arg], "MYADDR", inet_ntoa(bundle->ncp.ipcp.my_ip));
42938629Sbrian    nargv[arg] = subst(nargv[arg], "USER", bundle->ncp.mp.peer.authname);
43038629Sbrian    nargv[arg] = subst(nargv[arg], "PEER_ENDDISC",
43138629Sbrian                       mp_Enddisc(bundle->ncp.mp.peer.enddisc.class,
43238629Sbrian                                  bundle->ncp.mp.peer.enddisc.address,
43338629Sbrian                                  bundle->ncp.mp.peer.enddisc.len));
43438629Sbrian    nargv[arg] = subst(nargv[arg], "ENDDISC",
43538629Sbrian                       mp_Enddisc(bundle->ncp.mp.cfg.enddisc.class,
43638629Sbrian                                  bundle->ncp.mp.cfg.enddisc.address,
43738629Sbrian                                  bundle->ncp.mp.cfg.enddisc.len));
43847849Sbrian    nargv[arg] = subst(nargv[arg], "PROCESSID", pidstr);
43938629Sbrian    nargv[arg] = subst(nargv[arg], "LABEL", bundle_GetLabel(bundle));
44058044Sbrian    nargv[arg] = subst(nargv[arg], "DNS0",
44158044Sbrian                       inet_ntoa(bundle->ncp.ipcp.ns.dns[0]));
44258044Sbrian    nargv[arg] = subst(nargv[arg], "DNS1",
44358044Sbrian                       inet_ntoa(bundle->ncp.ipcp.ns.dns[1]));
44438628Sbrian  }
44538628Sbrian  nargv[arg] = NULL;
44638628Sbrian}
44738628Sbrian
44828536Sbrianstatic int
44931343SbrianShellCommand(struct cmdargs const *arg, int bg)
45010528Samurai{
45110528Samurai  const char *shell;
45247849Sbrian  pid_t shpid, pid;
45320813Sjkh
45418856Ssos#ifdef SHELL_ONLY_INTERACTIVELY
45526911Sbrian  /* we're only allowed to shell when we run ppp interactively */
45636285Sbrian  if (arg->prompt && arg->prompt->owner) {
45736285Sbrian    log_Printf(LogWARN, "Can't start a shell from a network connection\n");
45826516Sbrian    return 1;
45910528Samurai  }
46026911Sbrian#endif
46128679Sbrian
46236285Sbrian  if (arg->argc == arg->argn) {
46336285Sbrian    if (!arg->prompt) {
46436285Sbrian      log_Printf(LogWARN, "Can't start an interactive shell from"
46536285Sbrian                " a config file\n");
46628381Sbrian      return 1;
46736285Sbrian    } else if (arg->prompt->owner) {
46836285Sbrian      log_Printf(LogWARN, "Can't start an interactive shell from"
46936285Sbrian                " a socket connection\n");
47036285Sbrian      return 1;
47128381Sbrian    } else if (bg) {
47236285Sbrian      log_Printf(LogWARN, "Can only start an interactive shell in"
47328679Sbrian		" the foreground mode\n");
47428381Sbrian      return 1;
47528381Sbrian    }
47634536Sbrian  }
47734536Sbrian
47847849Sbrian  pid = getpid();
47928679Sbrian  if ((shpid = fork()) == 0) {
48036285Sbrian    int i, fd;
48118531Sbde
48236285Sbrian    if ((shell = getenv("SHELL")) == 0)
48336285Sbrian      shell = _PATH_BSHELL;
48432017Sbrian
48536285Sbrian    timer_TermService();
48636285Sbrian
48736285Sbrian    if (arg->prompt)
48836285Sbrian      fd = arg->prompt->fd_out;
48936285Sbrian    else if ((fd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
49036285Sbrian      log_Printf(LogALERT, "Failed to open %s: %s\n",
49136285Sbrian                _PATH_DEVNULL, strerror(errno));
49228679Sbrian      exit(1);
49328679Sbrian    }
49449976Sbrian    dup2(fd, STDIN_FILENO);
49549976Sbrian    dup2(fd, STDOUT_FILENO);
49649976Sbrian    dup2(fd, STDERR_FILENO);
49749976Sbrian    for (i = getdtablesize(); i > STDERR_FILENO; i--)
49849976Sbrian      fcntl(i, F_SETFD, 1);
49926516Sbrian
50055252Sbrian    setuid(ID0realuid());
50136285Sbrian    if (arg->argc > arg->argn) {
50228679Sbrian      /* substitute pseudo args */
50338628Sbrian      char *argv[MAXARGS];
50438628Sbrian      int argc = arg->argc - arg->argn;
50538628Sbrian
50638628Sbrian      if (argc >= sizeof argv / sizeof argv[0]) {
50738628Sbrian        argc = sizeof argv / sizeof argv[0] - 1;
50838628Sbrian        log_Printf(LogWARN, "Truncating shell command to %d args\n", argc);
50931343Sbrian      }
51047849Sbrian      command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 0, pid);
51128679Sbrian      if (bg) {
51228679Sbrian	pid_t p;
51310528Samurai
51428679Sbrian	p = getpid();
51528679Sbrian	if (daemon(1, 1) == -1) {
51636832Sbrian	  log_Printf(LogERROR, "%d: daemon: %s\n", (int)p, strerror(errno));
51728679Sbrian	  exit(1);
51828679Sbrian	}
51936285Sbrian      } else if (arg->prompt)
52036285Sbrian        printf("ppp: Pausing until %s finishes\n", arg->argv[arg->argn]);
52131343Sbrian      execvp(argv[0], argv);
52230316Sbrian    } else {
52336285Sbrian      if (arg->prompt)
52432017Sbrian        printf("ppp: Pausing until %s finishes\n", shell);
52536285Sbrian      prompt_TtyOldMode(arg->prompt);
52631343Sbrian      execl(shell, shell, NULL);
52730316Sbrian    }
52820813Sjkh
52940665Sbrian    log_Printf(LogWARN, "exec() of %s failed: %s\n",
53040665Sbrian              arg->argc > arg->argn ? arg->argv[arg->argn] : shell,
53140665Sbrian              strerror(errno));
53249976Sbrian    _exit(255);
53310528Samurai  }
53436285Sbrian
53536285Sbrian  if (shpid == (pid_t) - 1)
53636285Sbrian    log_Printf(LogERROR, "Fork failed: %s\n", strerror(errno));
53736285Sbrian  else {
53810528Samurai    int status;
53931343Sbrian    waitpid(shpid, &status, 0);
54010528Samurai  }
54120813Sjkh
54236285Sbrian  if (arg->prompt && !arg->prompt->owner)
54336285Sbrian    prompt_TtyCommandMode(arg->prompt);
54420813Sjkh
54536285Sbrian  return 0;
54610528Samurai}
54710528Samurai
54831343Sbrianstatic int
54931343SbrianBgShellCommand(struct cmdargs const *arg)
55031343Sbrian{
55136285Sbrian  if (arg->argc == arg->argn)
55231343Sbrian    return -1;
55331343Sbrian  return ShellCommand(arg, 1);
55431343Sbrian}
55531343Sbrian
55631343Sbrianstatic int
55731343SbrianFgShellCommand(struct cmdargs const *arg)
55831343Sbrian{
55931343Sbrian  return ShellCommand(arg, 0);
56031343Sbrian}
56131343Sbrian
56258044Sbrianstatic int
56358044SbrianResolvCommand(struct cmdargs const *arg)
56458044Sbrian{
56558044Sbrian  if (arg->argc == arg->argn + 1) {
56658044Sbrian    if (!strcasecmp(arg->argv[arg->argn], "reload"))
56758044Sbrian      ipcp_LoadDNS(&arg->bundle->ncp.ipcp);
56858044Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "restore"))
56958044Sbrian      ipcp_RestoreDNS(&arg->bundle->ncp.ipcp);
57058044Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "rewrite"))
57158044Sbrian      ipcp_WriteDNS(&arg->bundle->ncp.ipcp);
57258044Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "readonly"))
57358044Sbrian      arg->bundle->ncp.ipcp.ns.writable = 0;
57458044Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "writable"))
57558044Sbrian      arg->bundle->ncp.ipcp.ns.writable = 1;
57658044Sbrian    else
57758044Sbrian      return -1;
57858044Sbrian
57958044Sbrian    return 0;
58058044Sbrian  }
58158044Sbrian
58258044Sbrian  return -1;
58358044Sbrian}
58458044Sbrian
58550059Sbrian#ifndef NONAT
58658867Sbrianstatic struct cmdtab const NatCommands[] =
58740561Sbrian{
58850059Sbrian  {"addr", NULL, nat_RedirectAddr, LOCAL_AUTH,
58950059Sbrian   "static address translation", "nat addr [addr_local addr_alias]"},
59058867Sbrian  {"deny_incoming", NULL, NatOption, LOCAL_AUTH,
59150059Sbrian   "stop incoming connections", "nat deny_incoming yes|no",
59240561Sbrian   (const void *) PKT_ALIAS_DENY_INCOMING},
59358867Sbrian  {"enable", NULL, NatEnable, LOCAL_AUTH,
59450059Sbrian   "enable NAT", "nat enable yes|no"},
59558867Sbrian  {"log", NULL, NatOption, LOCAL_AUTH,
59650059Sbrian   "log NAT link creation", "nat log yes|no",
59740561Sbrian   (const void *) PKT_ALIAS_LOG},
59850059Sbrian  {"port", NULL, nat_RedirectPort, LOCAL_AUTH, "port redirection",
59950059Sbrian   "nat port proto localaddr:port[-port] aliasport[-aliasport]"},
60050059Sbrian  {"proxy", NULL, nat_ProxyRule, LOCAL_AUTH,
60150059Sbrian   "proxy control", "nat proxy server host[:port] ..."},
60258867Sbrian  {"same_ports", NULL, NatOption, LOCAL_AUTH,
60350059Sbrian   "try to leave port numbers unchanged", "nat same_ports yes|no",
60440561Sbrian   (const void *) PKT_ALIAS_SAME_PORTS},
60558867Sbrian  {"target", NULL, nat_SetTarget, LOCAL_AUTH,
60658867Sbrian   "Default address for incoming connections", "nat target addr" },
60758867Sbrian  {"unregistered_only", NULL, NatOption, LOCAL_AUTH,
60850059Sbrian   "translate unregistered (private) IP address space only",
60950059Sbrian   "nat unregistered_only yes|no",
61040561Sbrian   (const void *) PKT_ALIAS_UNREGISTERED_ONLY},
61158867Sbrian  {"use_sockets", NULL, NatOption, LOCAL_AUTH,
61250059Sbrian   "allocate host sockets", "nat use_sockets yes|no",
61340561Sbrian   (const void *) PKT_ALIAS_USE_SOCKETS},
61440561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
61558867Sbrian   "Display this message", "nat help|? [command]", NatCommands},
61640561Sbrian  {NULL, NULL, NULL},
61740561Sbrian};
61840561Sbrian#endif
61940561Sbrian
62040561Sbrianstatic struct cmdtab const AllowCommands[] = {
62140561Sbrian  {"modes", "mode", AllowModes, LOCAL_AUTH,
62240561Sbrian  "Only allow certain ppp modes", "allow modes mode..."},
62340561Sbrian  {"users", "user", AllowUsers, LOCAL_AUTH,
62440561Sbrian  "Only allow ppp access to certain users", "allow users logname..."},
62540561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
62640561Sbrian  "Display this message", "allow help|? [command]", AllowCommands},
62740561Sbrian  {NULL, NULL, NULL},
62840561Sbrian};
62940561Sbrian
63040561Sbrianstatic struct cmdtab const IfaceCommands[] =
63140561Sbrian{
63240561Sbrian  {"add", NULL, IfaceAddCommand, LOCAL_AUTH,
63340561Sbrian   "Add iface address", "iface add addr[/bits| mask] peer", NULL},
63440561Sbrian  {NULL, "add!", IfaceAddCommand, LOCAL_AUTH,
63540561Sbrian   "Add or change an iface address", "iface add! addr[/bits| mask] peer",
63640561Sbrian   (void *)1},
63740561Sbrian  {"clear", NULL, IfaceClearCommand, LOCAL_AUTH,
63840561Sbrian   "Clear iface address(es)", "iface clear"},
63940561Sbrian  {"delete", "rm", IfaceDeleteCommand, LOCAL_AUTH,
64040561Sbrian   "Delete iface address", "iface delete addr", NULL},
64140561Sbrian  {NULL, "rm!", IfaceDeleteCommand, LOCAL_AUTH,
64240561Sbrian   "Delete iface address", "iface delete addr", (void *)1},
64340561Sbrian  {NULL, "delete!", IfaceDeleteCommand, LOCAL_AUTH,
64440561Sbrian   "Delete iface address", "iface delete addr", (void *)1},
64540561Sbrian  {"show", NULL, iface_Show, LOCAL_AUTH,
64640561Sbrian   "Show iface address(es)", "iface show"},
64740561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
64850059Sbrian   "Display this message", "nat help|? [command]", IfaceCommands},
64940561Sbrian  {NULL, NULL, NULL},
65040561Sbrian};
65140561Sbrian
65230715Sbrianstatic struct cmdtab const Commands[] = {
65336285Sbrian  {"accept", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
65428679Sbrian  "accept option request", "accept option .."},
65528679Sbrian  {"add", NULL, AddCommand, LOCAL_AUTH,
65632109Sbrian  "add route", "add dest mask gateway", NULL},
65736285Sbrian  {NULL, "add!", AddCommand, LOCAL_AUTH,
65832109Sbrian  "add or change route", "add! dest mask gateway", (void *)1},
65940561Sbrian  {"allow", "auth", RunListCommand, LOCAL_AUTH,
66040561Sbrian  "Allow ppp access", "allow users|modes ....", AllowCommands},
66128679Sbrian  {"bg", "!bg", BgShellCommand, LOCAL_AUTH,
66231372Sbrian  "Run a background command", "[!]bg command"},
66336934Sbrian  {"clear", NULL, ClearCommand, LOCAL_AUTH | LOCAL_CX_OPT,
66446686Sbrian  "Clear throughput statistics",
66546686Sbrian  "clear ipcp|physical [current|overall|peak]..."},
66636285Sbrian  {"clone", NULL, CloneCommand, LOCAL_AUTH | LOCAL_CX,
66736285Sbrian  "Clone a link", "clone newname..."},
66836285Sbrian  {"close", NULL, CloseCommand, LOCAL_AUTH | LOCAL_CX_OPT,
66936285Sbrian  "Close an FSM", "close [lcp|ccp]"},
67028679Sbrian  {"delete", NULL, DeleteCommand, LOCAL_AUTH,
67132109Sbrian  "delete route", "delete dest", NULL},
67236285Sbrian  {NULL, "delete!", DeleteCommand, LOCAL_AUTH,
67332109Sbrian  "delete a route if it exists", "delete! dest", (void *)1},
67436285Sbrian  {"deny", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
67528679Sbrian  "Deny option request", "deny option .."},
67636285Sbrian  {"dial", "call", DialCommand, LOCAL_AUTH | LOCAL_CX_OPT,
67740797Sbrian  "Dial and login", "dial|call [system ...]", NULL},
67836285Sbrian  {"disable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
67928679Sbrian  "Disable option", "disable option .."},
68036285Sbrian  {"down", NULL, DownCommand, LOCAL_AUTH | LOCAL_CX_OPT,
68146686Sbrian  "Generate a down event", "down [ccp|lcp]"},
68236285Sbrian  {"enable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
68328679Sbrian  "Enable option", "enable option .."},
68440561Sbrian  {"iface", "interface", RunListCommand, LOCAL_AUTH,
68540561Sbrian  "interface control", "iface option ...", IfaceCommands},
68636285Sbrian  {"link", "datalink", LinkCommand, LOCAL_AUTH,
68736285Sbrian  "Link specific commands", "link name command ..."},
68837008Sbrian  {"load", NULL, LoadCommand, LOCAL_AUTH | LOCAL_CX_OPT,
68940797Sbrian  "Load settings", "load [system ...]"},
69050059Sbrian#ifndef NONAT
69150059Sbrian  {"nat", "alias", RunListCommand, LOCAL_AUTH,
69258867Sbrian  "NAT control", "nat option yes|no", NatCommands},
69350059Sbrian#endif
69436285Sbrian  {"open", NULL, OpenCommand, LOCAL_AUTH | LOCAL_CX_OPT,
69537955Sbrian  "Open an FSM", "open! [lcp|ccp|ipcp]", (void *)1},
69636285Sbrian  {"passwd", NULL, PasswdCommand, LOCAL_NO_AUTH,
69736285Sbrian  "Password for manipulation", "passwd LocalPassword"},
69836285Sbrian  {"quit", "bye", QuitCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
69936285Sbrian  "Quit PPP program", "quit|bye [all]"},
70036285Sbrian  {"remove", "rm", RemoveCommand, LOCAL_AUTH | LOCAL_CX,
70136285Sbrian  "Remove a link", "remove"},
70236285Sbrian  {"rename", "mv", RenameCommand, LOCAL_AUTH | LOCAL_CX,
70336285Sbrian  "Rename a link", "rename name"},
70458044Sbrian  {"resolv", NULL, ResolvCommand, LOCAL_AUTH,
70558044Sbrian  "Manipulate resolv.conf", "resolv readonly|reload|restore|rewrite|writable"},
70628679Sbrian  {"save", NULL, SaveCommand, LOCAL_AUTH,
70728679Sbrian  "Save settings", "save"},
70836285Sbrian  {"set", "setup", SetCommand, LOCAL_AUTH | LOCAL_CX_OPT,
70928679Sbrian  "Set parameters", "set[up] var value"},
71028679Sbrian  {"shell", "!", FgShellCommand, LOCAL_AUTH,
71128679Sbrian  "Run a subshell", "shell|! [sh command]"},
71236285Sbrian  {"show", NULL, ShowCommand, LOCAL_AUTH | LOCAL_CX_OPT,
71331372Sbrian  "Show status and stats", "show var"},
71436285Sbrian  {"term", NULL, TerminalCommand, LOCAL_AUTH | LOCAL_CX,
71531372Sbrian  "Enter terminal mode", "term"},
71628679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
71731343Sbrian  "Display this message", "help|? [command]", Commands},
71828679Sbrian  {NULL, NULL, NULL},
7196059Samurai};
7206059Samurai
72128536Sbrianstatic int
72231343SbrianShowEscape(struct cmdargs const *arg)
7236059Samurai{
72436285Sbrian  if (arg->cx->physical->async.cfg.EscMap[32]) {
72536285Sbrian    int code, bit;
72636285Sbrian    const char *sep = "";
7276059Samurai
72826516Sbrian    for (code = 0; code < 32; code++)
72936285Sbrian      if (arg->cx->physical->async.cfg.EscMap[code])
73028679Sbrian	for (bit = 0; bit < 8; bit++)
73136285Sbrian	  if (arg->cx->physical->async.cfg.EscMap[code] & (1 << bit)) {
73236285Sbrian	    prompt_Printf(arg->prompt, "%s0x%02x", sep, (code << 3) + bit);
73336285Sbrian            sep = ", ";
73436285Sbrian          }
73536285Sbrian    prompt_Printf(arg->prompt, "\n");
7366059Samurai  }
73731077Sbrian  return 0;
7386059Samurai}
7396059Samurai
74028679Sbrianstatic int
74136285SbrianShowTimerList(struct cmdargs const *arg)
7426059Samurai{
74336285Sbrian  timer_Show(0, arg->prompt);
74431077Sbrian  return 0;
7456059Samurai}
7466059Samurai
74728679Sbrianstatic int
74831343SbrianShowStopped(struct cmdargs const *arg)
74928327Sbrian{
75036285Sbrian  prompt_Printf(arg->prompt, " Stopped Timer:  LCP: ");
75136285Sbrian  if (!arg->cx->physical->link.lcp.fsm.StoppedTimer.load)
75236285Sbrian    prompt_Printf(arg->prompt, "Disabled");
75328327Sbrian  else
75436285Sbrian    prompt_Printf(arg->prompt, "%ld secs",
75536285Sbrian                  arg->cx->physical->link.lcp.fsm.StoppedTimer.load / SECTICKS);
75628461Sbrian
75736285Sbrian  prompt_Printf(arg->prompt, ", CCP: ");
75836285Sbrian  if (!arg->cx->physical->link.ccp.fsm.StoppedTimer.load)
75936285Sbrian    prompt_Printf(arg->prompt, "Disabled");
76028461Sbrian  else
76136285Sbrian    prompt_Printf(arg->prompt, "%ld secs",
76236285Sbrian                  arg->cx->physical->link.ccp.fsm.StoppedTimer.load / SECTICKS);
76328461Sbrian
76436285Sbrian  prompt_Printf(arg->prompt, "\n");
76528461Sbrian
76631077Sbrian  return 0;
76728327Sbrian}
76828327Sbrian
76928679Sbrianstatic int
77031343SbrianShowVersion(struct cmdargs const *arg)
7716059Samurai{
77251026Sbrian  prompt_Printf(arg->prompt, "PPP Version %s - %s\n", Version, __DATE__);
77331077Sbrian  return 0;
7746059Samurai}
7756059Samurai
77628679Sbrianstatic int
77736285SbrianShowProtocolStats(struct cmdargs const *arg)
77826326Sbrian{
77936285Sbrian  struct link *l = command_ChooseLink(arg);
78026326Sbrian
78136285Sbrian  prompt_Printf(arg->prompt, "%s:\n", l->name);
78236285Sbrian  link_ReportProtocolStatus(l, arg->prompt);
78331077Sbrian  return 0;
78426326Sbrian}
78526326Sbrian
78630715Sbrianstatic struct cmdtab const ShowCommands[] = {
78736285Sbrian  {"bundle", NULL, bundle_ShowStatus, LOCAL_AUTH,
78836285Sbrian  "bundle details", "show bundle"},
78936285Sbrian  {"ccp", NULL, ccp_ReportStatus, LOCAL_AUTH | LOCAL_CX_OPT,
79036285Sbrian  "CCP status", "show cpp"},
79136285Sbrian  {"compress", NULL, sl_Show, LOCAL_AUTH,
79236285Sbrian  "VJ compression stats", "show compress"},
79336285Sbrian  {"escape", NULL, ShowEscape, LOCAL_AUTH | LOCAL_CX,
79436285Sbrian  "escape characters", "show escape"},
79536285Sbrian  {"filter", NULL, filter_Show, LOCAL_AUTH,
79636285Sbrian  "packet filters", "show filter [in|out|dial|alive]"},
79736285Sbrian  {"hdlc", NULL, hdlc_ReportStatus, LOCAL_AUTH | LOCAL_CX,
79836285Sbrian  "HDLC errors", "show hdlc"},
79940561Sbrian  {"iface", "interface", iface_Show, LOCAL_AUTH,
80040561Sbrian  "Interface status", "show iface"},
80136285Sbrian  {"ipcp", NULL, ipcp_Show, LOCAL_AUTH,
80236285Sbrian  "IPCP status", "show ipcp"},
80347211Sbrian  {"layers", NULL, link_ShowLayers, LOCAL_AUTH | LOCAL_CX_OPT,
80447211Sbrian  "Protocol layers", "show layers"},
80536285Sbrian  {"lcp", NULL, lcp_ReportStatus, LOCAL_AUTH | LOCAL_CX,
80636285Sbrian  "LCP status", "show lcp"},
80736285Sbrian  {"link", "datalink", datalink_Show, LOCAL_AUTH | LOCAL_CX,
80836285Sbrian  "(high-level) link info", "show link"},
80936285Sbrian  {"links", NULL, bundle_ShowLinks, LOCAL_AUTH,
81036285Sbrian  "available link names", "show links"},
81136285Sbrian  {"log", NULL, log_ShowLevel, LOCAL_AUTH,
81236285Sbrian  "log levels", "show log"},
81336285Sbrian  {"mem", NULL, mbuf_Show, LOCAL_AUTH,
81436285Sbrian  "mbuf allocations", "show mem"},
81546686Sbrian  {"physical", NULL, physical_ShowStatus, LOCAL_AUTH | LOCAL_CX,
81646686Sbrian  "(low-level) link info", "show physical"},
81736285Sbrian  {"mp", "multilink", mp_ShowStatus, LOCAL_AUTH,
81836285Sbrian  "multilink setup", "show mp"},
81936285Sbrian  {"proto", NULL, ShowProtocolStats, LOCAL_AUTH | LOCAL_CX_OPT,
82036285Sbrian  "protocol summary", "show proto"},
82136285Sbrian  {"route", NULL, route_Show, LOCAL_AUTH,
82236285Sbrian  "routing table", "show route"},
82336285Sbrian  {"stopped", NULL, ShowStopped, LOCAL_AUTH | LOCAL_CX,
82436285Sbrian  "STOPPED timeout", "show stopped"},
82536285Sbrian  {"timers", NULL, ShowTimerList, LOCAL_AUTH,
82636285Sbrian  "alarm timers", "show timers"},
82728679Sbrian  {"version", NULL, ShowVersion, LOCAL_NO_AUTH | LOCAL_AUTH,
82836285Sbrian  "version string", "show version"},
82936285Sbrian  {"who", NULL, log_ShowWho, LOCAL_AUTH,
83036285Sbrian  "client list", "show who"},
83128679Sbrian  {"help", "?", HelpCommand, LOCAL_NO_AUTH | LOCAL_AUTH,
83231343Sbrian  "Display this message", "show help|? [command]", ShowCommands},
83328679Sbrian  {NULL, NULL, NULL},
8346059Samurai};
8356059Samurai
83630715Sbrianstatic struct cmdtab const *
83731343SbrianFindCommand(struct cmdtab const *cmds, const char *str, int *pmatch)
8386059Samurai{
83926516Sbrian  int nmatch;
84026516Sbrian  int len;
84128679Sbrian  struct cmdtab const *found;
8426059Samurai
84326516Sbrian  found = NULL;
84426516Sbrian  len = strlen(str);
84526516Sbrian  nmatch = 0;
8466059Samurai  while (cmds->func) {
84725566Sbrian    if (cmds->name && strncasecmp(str, cmds->name, len) == 0) {
84826516Sbrian      if (cmds->name[len] == '\0') {
84928679Sbrian	*pmatch = 1;
85028679Sbrian	return cmds;
85126516Sbrian      }
8526059Samurai      nmatch++;
8536059Samurai      found = cmds;
85428679Sbrian    } else if (cmds->alias && strncasecmp(str, cmds->alias, len) == 0) {
85526516Sbrian      if (cmds->alias[len] == '\0') {
85628679Sbrian	*pmatch = 1;
85728679Sbrian	return cmds;
85826516Sbrian      }
8596059Samurai      nmatch++;
8606059Samurai      found = cmds;
8616059Samurai    }
8626059Samurai    cmds++;
8636059Samurai  }
8646059Samurai  *pmatch = nmatch;
86526516Sbrian  return found;
8666059Samurai}
8676059Samurai
86836285Sbrianstatic const char *
86936285SbrianmkPrefix(int argc, char const *const *argv, char *tgt, int sz)
87036285Sbrian{
87136285Sbrian  int f, tlen, len;
87236285Sbrian
87336285Sbrian  tlen = 0;
87436285Sbrian  for (f = 0; f < argc && tlen < sz - 2; f++) {
87536285Sbrian    if (f)
87636285Sbrian      tgt[tlen++] = ' ';
87736285Sbrian    len = strlen(argv[f]);
87836285Sbrian    if (len > sz - tlen - 1)
87936285Sbrian      len = sz - tlen - 1;
88036285Sbrian    strncpy(tgt+tlen, argv[f], len);
88136285Sbrian    tlen += len;
88236285Sbrian  }
88336285Sbrian  tgt[tlen] = '\0';
88436285Sbrian  return tgt;
88536285Sbrian}
88636285Sbrian
88730715Sbrianstatic int
88836285SbrianFindExec(struct bundle *bundle, struct cmdtab const *cmds, int argc, int argn,
88936285Sbrian         char const *const *argv, struct prompt *prompt, struct datalink *cx)
8906059Samurai{
89128679Sbrian  struct cmdtab const *cmd;
8926059Samurai  int val = 1;
8936059Samurai  int nmatch;
89431343Sbrian  struct cmdargs arg;
89536285Sbrian  char prefix[100];
8966059Samurai
89736285Sbrian  cmd = FindCommand(cmds, argv[argn], &nmatch);
8986059Samurai  if (nmatch > 1)
89936285Sbrian    log_Printf(LogWARN, "%s: Ambiguous command\n",
90036285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix));
90136285Sbrian  else if (cmd && (!prompt || (cmd->lauth & prompt->auth))) {
90236285Sbrian    if ((cmd->lauth & LOCAL_CX) && !cx)
90336285Sbrian      /* We've got no context, but we require it */
90436285Sbrian      cx = bundle2datalink(bundle, NULL);
90536285Sbrian
90636285Sbrian    if ((cmd->lauth & LOCAL_CX) && !cx)
90736285Sbrian      log_Printf(LogWARN, "%s: No context (use the `link' command)\n",
90836285Sbrian                mkPrefix(argn+1, argv, prefix, sizeof prefix));
90936285Sbrian    else {
91036285Sbrian      if (cx && !(cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
91136285Sbrian        log_Printf(LogWARN, "%s: Redundant context (%s) ignored\n",
91236285Sbrian                  mkPrefix(argn+1, argv, prefix, sizeof prefix), cx->name);
91336285Sbrian        cx = NULL;
91436285Sbrian      }
91536285Sbrian      arg.cmdtab = cmds;
91636285Sbrian      arg.cmd = cmd;
91736285Sbrian      arg.argc = argc;
91836285Sbrian      arg.argn = argn+1;
91936285Sbrian      arg.argv = argv;
92036285Sbrian      arg.bundle = bundle;
92136285Sbrian      arg.cx = cx;
92236285Sbrian      arg.prompt = prompt;
92336285Sbrian      val = (*cmd->func) (&arg);
92436285Sbrian    }
92531343Sbrian  } else
92636285Sbrian    log_Printf(LogWARN, "%s: Invalid command\n",
92736285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix));
92826516Sbrian
92926516Sbrian  if (val == -1)
93036285Sbrian    log_Printf(LogWARN, "Usage: %s\n", cmd->syntax);
93128679Sbrian  else if (val)
93236285Sbrian    log_Printf(LogWARN, "%s: Failed %d\n",
93336285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix), val);
93426516Sbrian
93526516Sbrian  return val;
9366059Samurai}
9376059Samurai
93837009Sbrianint
93958045Sbriancommand_Expand_Interpret(char *buff, int nb, char *argv[MAXARGS], int offset)
94058045Sbrian{
94158045Sbrian  char buff2[LINE_LEN-offset];
94258045Sbrian
94358045Sbrian  InterpretArg(buff, buff2);
94458045Sbrian  strncpy(buff, buff2, LINE_LEN - offset - 1);
94558045Sbrian  buff[LINE_LEN - offset - 1] = '\0';
94658045Sbrian
94758045Sbrian  return command_Interpret(buff, nb, argv);
94858045Sbrian}
94958045Sbrian
95058045Sbrianint
95137009Sbriancommand_Interpret(char *buff, int nb, char *argv[MAXARGS])
9526059Samurai{
9536059Samurai  char *cp;
9546059Samurai
9556059Samurai  if (nb > 0) {
9566059Samurai    cp = buff + strcspn(buff, "\r\n");
9576059Samurai    if (cp)
9586059Samurai      *cp = '\0';
95955145Sbrian    return MakeArgs(buff, argv, MAXARGS, PARSE_REDUCE);
96037009Sbrian  }
96137009Sbrian  return 0;
96231121Sbrian}
9636059Samurai
96431822Sbrianstatic int
96531822Sbrianarghidden(int argc, char const *const *argv, int n)
96631822Sbrian{
96731822Sbrian  /* Is arg n of the given command to be hidden from the log ? */
96831828Sbrian
96931828Sbrian  /* set authkey xxxxx */
97031828Sbrian  /* set key xxxxx */
97131822Sbrian  if (n == 2 && !strncasecmp(argv[0], "se", 2) &&
97231822Sbrian      (!strncasecmp(argv[1], "authk", 5) || !strncasecmp(argv[1], "ke", 2)))
97331822Sbrian    return 1;
97431822Sbrian
97531828Sbrian  /* passwd xxxxx */
97631828Sbrian  if (n == 1 && !strncasecmp(argv[0], "p", 1))
97731828Sbrian    return 1;
97831828Sbrian
97936285Sbrian  /* set server port xxxxx .... */
98036285Sbrian  if (n == 3 && !strncasecmp(argv[0], "se", 2) &&
98136285Sbrian      !strncasecmp(argv[1], "se", 2))
98236285Sbrian    return 1;
98336285Sbrian
98431822Sbrian  return 0;
98531822Sbrian}
98631822Sbrian
98731121Sbrianvoid
98836285Sbriancommand_Run(struct bundle *bundle, int argc, char const *const *argv,
98937008Sbrian           struct prompt *prompt, const char *label, struct datalink *cx)
99031121Sbrian{
99131156Sbrian  if (argc > 0) {
99236285Sbrian    if (log_IsKept(LogCOMMAND)) {
99347844Sbrian      char buf[LINE_LEN];
99431156Sbrian      int f, n;
99531156Sbrian
99631156Sbrian      if (label) {
99731962Sbrian        strncpy(buf, label, sizeof buf - 3);
99831962Sbrian        buf[sizeof buf - 3] = '\0';
99931156Sbrian        strcat(buf, ": ");
100047844Sbrian        n = strlen(buf);
100147844Sbrian      } else {
100247844Sbrian        *buf = '\0';
100347844Sbrian        n = 0;
100431156Sbrian      }
100547844Sbrian      buf[sizeof buf - 1] = '\0';	/* In case we run out of room in buf */
100647844Sbrian
100731156Sbrian      for (f = 0; f < argc; f++) {
100831962Sbrian        if (n < sizeof buf - 1 && f)
100931156Sbrian          buf[n++] = ' ';
101031822Sbrian        if (arghidden(argc, argv, f))
101136285Sbrian          strncpy(buf+n, "********", sizeof buf - n - 1);
101231822Sbrian        else
101331962Sbrian          strncpy(buf+n, argv[f], sizeof buf - n - 1);
101431156Sbrian        n += strlen(buf+n);
101531156Sbrian      }
101636285Sbrian      log_Printf(LogCOMMAND, "%s\n", buf);
101731156Sbrian    }
101837008Sbrian    FindExec(bundle, Commands, argc, 0, argv, prompt, cx);
101931156Sbrian  }
10206059Samurai}
10216059Samurai
102254914Sbrianint
102336285Sbriancommand_Decode(struct bundle *bundle, char *buff, int nb, struct prompt *prompt,
102436285Sbrian              const char *label)
102531121Sbrian{
102631121Sbrian  int argc;
102737009Sbrian  char *argv[MAXARGS];
102831121Sbrian
102958045Sbrian  if ((argc = command_Expand_Interpret(buff, nb, argv, 0)) < 0)
103054914Sbrian    return 0;
103154914Sbrian
103237008Sbrian  command_Run(bundle, argc, (char const *const *)argv, prompt, label, NULL);
103354914Sbrian  return 1;
103431121Sbrian}
103531121Sbrian
10366059Samuraistatic int
103731343SbrianShowCommand(struct cmdargs const *arg)
10386059Samurai{
103936285Sbrian  if (!arg->prompt)
104036285Sbrian    log_Printf(LogWARN, "show: Cannot show without a prompt\n");
104136285Sbrian  else if (arg->argc > arg->argn)
104236285Sbrian    FindExec(arg->bundle, ShowCommands, arg->argc, arg->argn, arg->argv,
104336285Sbrian             arg->prompt, arg->cx);
10446059Samurai  else
104536285Sbrian    prompt_Printf(arg->prompt, "Use ``show ?'' to get a list.\n");
104626516Sbrian
104726516Sbrian  return 0;
10486059Samurai}
10496059Samurai
10506059Samuraistatic int
105131343SbrianTerminalCommand(struct cmdargs const *arg)
10526059Samurai{
105336285Sbrian  if (!arg->prompt) {
105436285Sbrian    log_Printf(LogWARN, "term: Need a prompt\n");
105526516Sbrian    return 1;
10566059Samurai  }
105736285Sbrian
105836285Sbrian  if (arg->cx->physical->link.lcp.fsm.state > ST_CLOSED) {
105936285Sbrian    prompt_Printf(arg->prompt, "LCP state is [%s]\n",
106036285Sbrian                  State2Nam(arg->cx->physical->link.lcp.fsm.state));
106136285Sbrian    return 1;
10626059Samurai  }
106336285Sbrian
106436285Sbrian  datalink_Up(arg->cx, 0, 0);
106536285Sbrian  prompt_TtyTermMode(arg->prompt, arg->cx);
106636285Sbrian  return 0;
10676059Samurai}
10686059Samurai
10696059Samuraistatic int
107031343SbrianQuitCommand(struct cmdargs const *arg)
10716059Samurai{
107236285Sbrian  if (!arg->prompt || prompt_IsController(arg->prompt) ||
107336285Sbrian      (arg->argc > arg->argn && !strcasecmp(arg->argv[arg->argn], "all") &&
107436285Sbrian       (arg->prompt->auth & LOCAL_AUTH)))
107536285Sbrian    Cleanup(EX_NORMAL);
107636285Sbrian  if (arg->prompt)
107736285Sbrian    prompt_Destroy(arg->prompt, 1);
107826516Sbrian
107926516Sbrian  return 0;
10806059Samurai}
10816059Samurai
10826059Samuraistatic int
108336285SbrianOpenCommand(struct cmdargs const *arg)
10846059Samurai{
108537160Sbrian  if (arg->argc == arg->argn)
108637993Sbrian    bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1);
108737160Sbrian  else if (arg->argc == arg->argn + 1) {
108837160Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp")) {
108937385Sbrian      struct datalink *cx = arg->cx ?
109037385Sbrian        arg->cx : bundle2datalink(arg->bundle, NULL);
109137385Sbrian      if (cx) {
109237385Sbrian        if (cx->physical->link.lcp.fsm.state == ST_OPENED)
109337385Sbrian          fsm_Reopen(&cx->physical->link.lcp.fsm);
109437160Sbrian        else
109537993Sbrian          bundle_Open(arg->bundle, cx->name, PHYS_ALL, 1);
109637160Sbrian      } else
109737160Sbrian        log_Printf(LogWARN, "open lcp: You must specify a link\n");
109837160Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) {
109937160Sbrian      struct fsm *fp;
11006059Samurai
110137210Sbrian      fp = &command_ChooseLink(arg)->ccp.fsm;
110237160Sbrian      if (fp->link->lcp.fsm.state != ST_OPENED)
110337160Sbrian        log_Printf(LogWARN, "open: LCP must be open before opening CCP\n");
110437160Sbrian      else if (fp->state == ST_OPENED)
110537160Sbrian        fsm_Reopen(fp);
110637160Sbrian      else {
110737160Sbrian        fp->open_mode = 0;	/* Not passive any more */
110837160Sbrian        if (fp->state == ST_STOPPED) {
110937160Sbrian          fsm_Down(fp);
111037160Sbrian          fsm_Up(fp);
111137160Sbrian        } else {
111237160Sbrian          fsm_Up(fp);
111337160Sbrian          fsm_Open(fp);
111437160Sbrian        }
111536285Sbrian      }
111637160Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ipcp")) {
111737160Sbrian      if (arg->cx)
111837160Sbrian        log_Printf(LogWARN, "open ipcp: You need not specify a link\n");
111937160Sbrian      if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED)
112037160Sbrian        fsm_Reopen(&arg->bundle->ncp.ipcp.fsm);
112137160Sbrian      else
112237993Sbrian        bundle_Open(arg->bundle, NULL, PHYS_ALL, 1);
112337160Sbrian    } else
112437160Sbrian      return -1;
112536285Sbrian  } else
112636285Sbrian    return -1;
112736285Sbrian
112826516Sbrian  return 0;
11296059Samurai}
11306059Samurai
113125067Sbrianstatic int
113236285SbrianCloseCommand(struct cmdargs const *arg)
11336059Samurai{
113437007Sbrian  if (arg->argc == arg->argn)
113537007Sbrian    bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_STAYDOWN);
113637007Sbrian  else if (arg->argc == arg->argn + 1) {
113737007Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp"))
113837007Sbrian      bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_LCP);
113937007Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "ccp") ||
114037007Sbrian             !strcasecmp(arg->argv[arg->argn], "ccp!")) {
114137007Sbrian      struct fsm *fp;
11426059Samurai
114337210Sbrian      fp = &command_ChooseLink(arg)->ccp.fsm;
114437007Sbrian      if (fp->state == ST_OPENED) {
114537007Sbrian        fsm_Close(fp);
114637007Sbrian        if (arg->argv[arg->argn][3] == '!')
114737007Sbrian          fp->open_mode = 0;		/* Stay ST_CLOSED */
114837007Sbrian        else
114937007Sbrian          fp->open_mode = OPEN_PASSIVE;	/* Wait for the peer to start */
115037007Sbrian      }
115137007Sbrian    } else
115236285Sbrian      return -1;
115336285Sbrian  } else
115436285Sbrian    return -1;
115536285Sbrian
115636285Sbrian  return 0;
11576059Samurai}
11586059Samurai
115925067Sbrianstatic int
116036285SbrianDownCommand(struct cmdargs const *arg)
116111336Samurai{
116237018Sbrian  if (arg->argc == arg->argn) {
116337018Sbrian      if (arg->cx)
116437018Sbrian        datalink_Down(arg->cx, CLOSE_STAYDOWN);
116537018Sbrian      else
116637018Sbrian        bundle_Down(arg->bundle, CLOSE_STAYDOWN);
116737018Sbrian  } else if (arg->argc == arg->argn + 1) {
116837018Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp")) {
116937018Sbrian      if (arg->cx)
117037018Sbrian        datalink_Down(arg->cx, CLOSE_LCP);
117137018Sbrian      else
117237018Sbrian        bundle_Down(arg->bundle, CLOSE_LCP);
117337018Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) {
117437018Sbrian      struct fsm *fp = arg->cx ? &arg->cx->physical->link.ccp.fsm :
117537018Sbrian                                 &arg->bundle->ncp.mp.link.ccp.fsm;
117637060Sbrian      fsm2initial(fp);
117737018Sbrian    } else
117837018Sbrian      return -1;
117936285Sbrian  } else
118036285Sbrian    return -1;
118136285Sbrian
118236285Sbrian  return 0;
118325067Sbrian}
118425067Sbrian
118525067Sbrianstatic int
118636285SbrianSetModemSpeed(struct cmdargs const *arg)
118725067Sbrian{
118836285Sbrian  long speed;
118936285Sbrian  char *end;
119011336Samurai
119136285Sbrian  if (arg->argc > arg->argn && *arg->argv[arg->argn]) {
119236285Sbrian    if (arg->argc > arg->argn+1) {
119354917Sbrian      log_Printf(LogWARN, "SetModemSpeed: Too many arguments\n");
119436285Sbrian      return -1;
119511336Samurai    }
119636285Sbrian    if (strcasecmp(arg->argv[arg->argn], "sync") == 0) {
119736285Sbrian      physical_SetSync(arg->cx->physical);
119836285Sbrian      return 0;
119936285Sbrian    }
120036285Sbrian    end = NULL;
120136285Sbrian    speed = strtol(arg->argv[arg->argn], &end, 10);
120236285Sbrian    if (*end) {
120336285Sbrian      log_Printf(LogWARN, "SetModemSpeed: Bad argument \"%s\"",
120436285Sbrian                arg->argv[arg->argn]);
120536285Sbrian      return -1;
120636285Sbrian    }
120736285Sbrian    if (physical_SetSpeed(arg->cx->physical, speed))
120836285Sbrian      return 0;
120936285Sbrian    log_Printf(LogWARN, "%s: Invalid speed\n", arg->argv[arg->argn]);
121036285Sbrian  } else
121136285Sbrian    log_Printf(LogWARN, "SetModemSpeed: No speed specified\n");
121224939Sbrian
121326516Sbrian  return -1;
121411336Samurai}
121511336Samurai
121625067Sbrianstatic int
121731343SbrianSetStoppedTimeout(struct cmdargs const *arg)
121828327Sbrian{
121936285Sbrian  struct link *l = &arg->cx->physical->link;
122036285Sbrian
122136285Sbrian  l->lcp.fsm.StoppedTimer.load = 0;
122236285Sbrian  l->ccp.fsm.StoppedTimer.load = 0;
122336285Sbrian  if (arg->argc <= arg->argn+2) {
122436285Sbrian    if (arg->argc > arg->argn) {
122536285Sbrian      l->lcp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn]) * SECTICKS;
122636285Sbrian      if (arg->argc > arg->argn+1)
122736285Sbrian        l->ccp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn+1]) * SECTICKS;
122828461Sbrian    }
122928327Sbrian    return 0;
123028327Sbrian  }
123128327Sbrian  return -1;
123228327Sbrian}
123328327Sbrian
123428327Sbrianstatic int
123531343SbrianSetServer(struct cmdargs const *arg)
123626940Sbrian{
123726940Sbrian  int res = -1;
123826940Sbrian
123936285Sbrian  if (arg->argc > arg->argn && arg->argc < arg->argn+4) {
124031081Sbrian    const char *port, *passwd, *mask;
124153125Sbrian    int mlen;
124231081Sbrian
124331081Sbrian    /* What's what ? */
124436285Sbrian    port = arg->argv[arg->argn];
124536285Sbrian    if (arg->argc == arg->argn + 2) {
124636285Sbrian      passwd = arg->argv[arg->argn+1];
124736285Sbrian      mask = NULL;
124836285Sbrian    } else if (arg->argc == arg->argn + 3) {
124936285Sbrian      passwd = arg->argv[arg->argn+1];
125036285Sbrian      mask = arg->argv[arg->argn+2];
125153125Sbrian      mlen = strlen(mask);
125253125Sbrian      if (mlen == 0 || mlen > 4 || strspn(mask, "01234567") != mlen ||
125353125Sbrian          (mlen == 4 && *mask != '0')) {
125453125Sbrian        log_Printf(LogWARN, "%s %s: %s: Invalid mask\n",
125553125Sbrian                   arg->argv[arg->argn - 2], arg->argv[arg->argn - 1], mask);
125631081Sbrian        return -1;
125753125Sbrian      }
125836285Sbrian    } else if (strcasecmp(port, "none") == 0) {
125936285Sbrian      if (server_Close(arg->bundle))
126036285Sbrian        log_Printf(LogPHASE, "Disabled server port.\n");
126136285Sbrian      return 0;
126231081Sbrian    } else
126336285Sbrian      return -1;
126431081Sbrian
126536285Sbrian    strncpy(server.passwd, passwd, sizeof server.passwd - 1);
126636285Sbrian    server.passwd[sizeof server.passwd - 1] = '\0';
126731081Sbrian
126836285Sbrian    if (*port == '/') {
126931081Sbrian      mode_t imask;
127036285Sbrian      char *ptr, name[LINE_LEN + 12];
127128679Sbrian
127253125Sbrian      if (mask == NULL)
127331081Sbrian        imask = (mode_t)-1;
127453125Sbrian      else for (imask = mlen = 0; mask[mlen]; mlen++)
127553125Sbrian        imask = (imask * 8) + mask[mlen] - '0';
127636285Sbrian
127736285Sbrian      ptr = strstr(port, "%d");
127836285Sbrian      if (ptr) {
127936285Sbrian        snprintf(name, sizeof name, "%.*s%d%s",
128037210Sbrian                 (int)(ptr - port), port, arg->bundle->unit, ptr + 2);
128136285Sbrian        port = name;
128236285Sbrian      }
128336285Sbrian      res = server_LocalOpen(arg->bundle, port, imask);
128427346Sbrian    } else {
128536285Sbrian      int iport, add = 0;
128628679Sbrian
128731081Sbrian      if (mask != NULL)
128831081Sbrian        return -1;
128928679Sbrian
129036285Sbrian      if (*port == '+') {
129136285Sbrian        port++;
129236285Sbrian        add = 1;
129336285Sbrian      }
129431081Sbrian      if (strspn(port, "0123456789") != strlen(port)) {
129531081Sbrian        struct servent *s;
129631081Sbrian
129731081Sbrian        if ((s = getservbyname(port, "tcp")) == NULL) {
129831081Sbrian	  iport = 0;
129936285Sbrian	  log_Printf(LogWARN, "%s: Invalid port or service\n", port);
130028679Sbrian	} else
130131081Sbrian	  iport = ntohs(s->s_port);
130227346Sbrian      } else
130331081Sbrian        iport = atoi(port);
130436285Sbrian
130536285Sbrian      if (iport) {
130636285Sbrian        if (add)
130736285Sbrian          iport += arg->bundle->unit;
130836285Sbrian        res = server_TcpOpen(arg->bundle, iport);
130936285Sbrian      } else
131036285Sbrian        res = -1;
131127346Sbrian    }
131231081Sbrian  }
131326940Sbrian
131426940Sbrian  return res;
131526940Sbrian}
131626940Sbrian
131726940Sbrianstatic int
131831343SbrianSetEscape(struct cmdargs const *arg)
13196059Samurai{
13206059Samurai  int code;
132136285Sbrian  int argc = arg->argc - arg->argn;
132236285Sbrian  char const *const *argv = arg->argv + arg->argn;
13236059Samurai
13246059Samurai  for (code = 0; code < 33; code++)
132536285Sbrian    arg->cx->physical->async.cfg.EscMap[code] = 0;
132631343Sbrian
13276059Samurai  while (argc-- > 0) {
13286059Samurai    sscanf(*argv++, "%x", &code);
13296059Samurai    code &= 0xff;
133036285Sbrian    arg->cx->physical->async.cfg.EscMap[code >> 3] |= (1 << (code & 7));
133136285Sbrian    arg->cx->physical->async.cfg.EscMap[32] = 1;
13326059Samurai  }
133326516Sbrian  return 0;
13346059Samurai}
13356059Samurai
13366059Samuraistatic int
133731343SbrianSetInterfaceAddr(struct cmdargs const *arg)
13386059Samurai{
133936285Sbrian  struct ipcp *ipcp = &arg->bundle->ncp.ipcp;
134032267Sbrian  const char *hisaddr;
134132267Sbrian
134240561Sbrian  if (arg->argc > arg->argn + 4)
134340561Sbrian    return -1;
134440561Sbrian
134532267Sbrian  hisaddr = NULL;
134644874Sbrian  memset(&ipcp->cfg.my_range, '\0', sizeof ipcp->cfg.my_range);
134744874Sbrian  memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
134836285Sbrian  ipcp->cfg.HaveTriggerAddress = 0;
134936285Sbrian  ipcp->cfg.netmask.s_addr = INADDR_ANY;
135036285Sbrian  iplist_reset(&ipcp->cfg.peer_list);
135128394Sbrian
135236285Sbrian  if (arg->argc > arg->argn) {
135343313Sbrian    if (!ParseAddr(ipcp, arg->argv[arg->argn],
135436285Sbrian                   &ipcp->cfg.my_range.ipaddr, &ipcp->cfg.my_range.mask,
135536285Sbrian                   &ipcp->cfg.my_range.width))
135628679Sbrian      return 1;
135736285Sbrian    if (arg->argc > arg->argn+1) {
135836285Sbrian      hisaddr = arg->argv[arg->argn+1];
135936285Sbrian      if (arg->argc > arg->argn+2) {
136044455Sbrian        ipcp->ifmask = ipcp->cfg.netmask = GetIpAddr(arg->argv[arg->argn+2]);
136136285Sbrian	if (arg->argc > arg->argn+3) {
136236285Sbrian	  ipcp->cfg.TriggerAddress = GetIpAddr(arg->argv[arg->argn+3]);
136336285Sbrian	  ipcp->cfg.HaveTriggerAddress = 1;
13649440Samurai	}
13656059Samurai      }
13666059Samurai    }
13676059Samurai  }
136828394Sbrian
136940561Sbrian  /* 0.0.0.0 means any address (0 bits) */
137036285Sbrian  if (ipcp->cfg.my_range.ipaddr.s_addr == INADDR_ANY) {
137136285Sbrian    ipcp->cfg.my_range.mask.s_addr = INADDR_ANY;
137236285Sbrian    ipcp->cfg.my_range.width = 0;
13736059Samurai  }
137436285Sbrian  ipcp->my_ip.s_addr = ipcp->cfg.my_range.ipaddr.s_addr;
137547648Sbrian  bundle_AdjustFilters(arg->bundle, &ipcp->my_ip, NULL);
137636285Sbrian
137736285Sbrian  if (hisaddr && !ipcp_UseHisaddr(arg->bundle, hisaddr,
137836928Sbrian                                  arg->bundle->phys_type.all & PHYS_AUTO))
137932267Sbrian    return 4;
138031121Sbrian
138126516Sbrian  return 0;
13826059Samurai}
13836059Samurai
138418752Sjkhstatic int
138544305SbrianSetRetry(int argc, char const *const *argv, u_int *timeout, u_int *maxreq,
138644305Sbrian          u_int *maxtrm, int def)
138744305Sbrian{
138844305Sbrian  if (argc == 0) {
138944305Sbrian    *timeout = DEF_FSMRETRY;
139044305Sbrian    *maxreq = def;
139144305Sbrian    if (maxtrm != NULL)
139244305Sbrian      *maxtrm = def;
139344305Sbrian  } else {
139444305Sbrian    long l = atol(argv[0]);
139544305Sbrian
139644305Sbrian    if (l < MIN_FSMRETRY) {
139744305Sbrian      log_Printf(LogWARN, "%ld: Invalid FSM retry period - min %d\n",
139844305Sbrian                 l, MIN_FSMRETRY);
139944305Sbrian      return 1;
140044305Sbrian    } else
140144305Sbrian      *timeout = l;
140244305Sbrian
140344305Sbrian    if (argc > 1) {
140444305Sbrian      l = atol(argv[1]);
140544305Sbrian      if (l < 1) {
140644305Sbrian        log_Printf(LogWARN, "%ld: Invalid FSM REQ tries - changed to 1\n", l);
140744305Sbrian        l = 1;
140844305Sbrian      }
140944305Sbrian      *maxreq = l;
141044305Sbrian
141144305Sbrian      if (argc > 2 && maxtrm != NULL) {
141244305Sbrian        l = atol(argv[2]);
141344305Sbrian        if (l < 1) {
141444305Sbrian          log_Printf(LogWARN, "%ld: Invalid FSM TRM tries - changed to 1\n", l);
141544305Sbrian          l = 1;
141644305Sbrian        }
141744305Sbrian        *maxtrm = l;
141844305Sbrian      }
141944305Sbrian    }
142044305Sbrian  }
142144305Sbrian
142244305Sbrian  return 0;
142344305Sbrian}
142444305Sbrian
142544305Sbrianstatic int
142631343SbrianSetVariable(struct cmdargs const *arg)
14276059Samurai{
142837210Sbrian  long long_val, param = (long)arg->cmd->args;
142951048Sbrian  int mode, dummyint, f, first;
143031343Sbrian  const char *argp;
143136285Sbrian  struct datalink *cx = arg->cx;	/* LOCAL_CX uses this */
143236285Sbrian  const char *err = NULL;
143336285Sbrian  struct link *l = command_ChooseLink(arg);	/* LOCAL_CX_OPT uses this */
143436285Sbrian  struct in_addr dummyaddr, *addr;
14356059Samurai
143636285Sbrian  if (arg->argc > arg->argn)
143736285Sbrian    argp = arg->argv[arg->argn];
143826551Sbrian  else
143931343Sbrian    argp = "";
144026551Sbrian
144136285Sbrian  if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
144236285Sbrian    log_Printf(LogWARN, "set %s: No context (use the `link' command)\n",
144336285Sbrian              arg->cmd->name);
144436285Sbrian    return 1;
144536285Sbrian  } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
144636285Sbrian    log_Printf(LogWARN, "set %s: Redundant context (%s) ignored\n",
144736285Sbrian              arg->cmd->name, cx->name);
144836285Sbrian    cx = NULL;
144936285Sbrian  }
145036285Sbrian
145126551Sbrian  switch (param) {
145228679Sbrian  case VAR_AUTHKEY:
145350139Sbrian    strncpy(arg->bundle->cfg.auth.key, argp,
145450139Sbrian            sizeof arg->bundle->cfg.auth.key - 1);
145550139Sbrian    arg->bundle->cfg.auth.key[sizeof arg->bundle->cfg.auth.key - 1] = '\0';
145628679Sbrian    break;
145737210Sbrian
145828679Sbrian  case VAR_AUTHNAME:
145940622Sbrian    switch (bundle_Phase(arg->bundle)) {
146058880Sbrian      default:
146158880Sbrian        log_Printf(LogWARN, "Altering authname while at phase %s\n",
146258880Sbrian                   bundle_PhaseName(arg->bundle));
146358880Sbrian        /* drop through */
146440622Sbrian      case PHASE_DEAD:
146540622Sbrian      case PHASE_ESTABLISH:
146640622Sbrian        strncpy(arg->bundle->cfg.auth.name, argp,
146740622Sbrian                sizeof arg->bundle->cfg.auth.name - 1);
146840622Sbrian        arg->bundle->cfg.auth.name[sizeof arg->bundle->cfg.auth.name-1] = '\0';
146940622Sbrian        break;
147036285Sbrian    }
147128679Sbrian    break;
147237210Sbrian
147336285Sbrian  case VAR_AUTOLOAD:
147449434Sbrian    if (arg->argc == arg->argn + 3) {
147549434Sbrian      int v1, v2, v3;
147649434Sbrian      char *end;
147749434Sbrian
147849434Sbrian      v1 = strtol(arg->argv[arg->argn], &end, 0);
147949434Sbrian      if (v1 < 0 || *end) {
148049434Sbrian        log_Printf(LogWARN, "autoload: %s: Invalid min percentage\n",
148149434Sbrian                   arg->argv[arg->argn]);
148249434Sbrian        return 1;
148336285Sbrian      }
148449434Sbrian
148549434Sbrian      v2 = strtol(arg->argv[arg->argn + 1], &end, 0);
148649434Sbrian      if (v2 < 0 || *end) {
148749434Sbrian        log_Printf(LogWARN, "autoload: %s: Invalid max percentage\n",
148849434Sbrian                   arg->argv[arg->argn + 1]);
148949434Sbrian        return 1;
149049434Sbrian      }
149149434Sbrian      if (v2 < v1) {
149249434Sbrian        v3 = v1;
149349434Sbrian        v1 = v2;
149449434Sbrian        v2 = v3;
149549434Sbrian      }
149649434Sbrian
149749434Sbrian      v3 = strtol(arg->argv[arg->argn + 2], &end, 0);
149849434Sbrian      if (v3 <= 0 || *end) {
149949434Sbrian        log_Printf(LogWARN, "autoload: %s: Invalid throughput period\n",
150049434Sbrian                   arg->argv[arg->argn + 2]);
150149434Sbrian        return 1;
150249434Sbrian      }
150349434Sbrian
150449434Sbrian      arg->bundle->ncp.mp.cfg.autoload.min = v1;
150549434Sbrian      arg->bundle->ncp.mp.cfg.autoload.max = v2;
150649434Sbrian      arg->bundle->ncp.mp.cfg.autoload.period = v3;
150749434Sbrian      mp_RestartAutoloadTimer(&arg->bundle->ncp.mp);
150836285Sbrian    } else {
150949434Sbrian      err = "Set autoload requires three arguments\n";
151036285Sbrian      log_Printf(LogWARN, err);
151136285Sbrian    }
151236285Sbrian    break;
151337210Sbrian
151428679Sbrian  case VAR_DIAL:
151536285Sbrian    strncpy(cx->cfg.script.dial, argp, sizeof cx->cfg.script.dial - 1);
151636285Sbrian    cx->cfg.script.dial[sizeof cx->cfg.script.dial - 1] = '\0';
151728679Sbrian    break;
151837210Sbrian
151928679Sbrian  case VAR_LOGIN:
152036285Sbrian    strncpy(cx->cfg.script.login, argp, sizeof cx->cfg.script.login - 1);
152136285Sbrian    cx->cfg.script.login[sizeof cx->cfg.script.login - 1] = '\0';
152228679Sbrian    break;
152337210Sbrian
152436285Sbrian  case VAR_WINSIZE:
152536285Sbrian    if (arg->argc > arg->argn) {
152636285Sbrian      l->ccp.cfg.deflate.out.winsize = atoi(arg->argv[arg->argn]);
152736285Sbrian      if (l->ccp.cfg.deflate.out.winsize < 8 ||
152836285Sbrian          l->ccp.cfg.deflate.out.winsize > 15) {
152936285Sbrian          log_Printf(LogWARN, "%d: Invalid outgoing window size\n",
153036285Sbrian                    l->ccp.cfg.deflate.out.winsize);
153136285Sbrian          l->ccp.cfg.deflate.out.winsize = 15;
153236285Sbrian      }
153336285Sbrian      if (arg->argc > arg->argn+1) {
153436285Sbrian        l->ccp.cfg.deflate.in.winsize = atoi(arg->argv[arg->argn+1]);
153536285Sbrian        if (l->ccp.cfg.deflate.in.winsize < 8 ||
153636285Sbrian            l->ccp.cfg.deflate.in.winsize > 15) {
153736285Sbrian            log_Printf(LogWARN, "%d: Invalid incoming window size\n",
153836285Sbrian                      l->ccp.cfg.deflate.in.winsize);
153936285Sbrian            l->ccp.cfg.deflate.in.winsize = 15;
154036285Sbrian        }
154136285Sbrian      } else
154236285Sbrian        l->ccp.cfg.deflate.in.winsize = 0;
154336285Sbrian    } else {
154436285Sbrian      err = "No window size specified\n";
154536285Sbrian      log_Printf(LogWARN, err);
154636285Sbrian    }
154736285Sbrian    break;
154837210Sbrian
154928679Sbrian  case VAR_DEVICE:
155036285Sbrian    physical_SetDeviceList(cx->physical, arg->argc - arg->argn,
155136285Sbrian                           arg->argv + arg->argn);
155236285Sbrian    break;
155337210Sbrian
155436285Sbrian  case VAR_ACCMAP:
155536285Sbrian    if (arg->argc > arg->argn) {
155637210Sbrian      u_long ulong_val;
155736285Sbrian      sscanf(argp, "%lx", &ulong_val);
155837210Sbrian      cx->physical->link.lcp.cfg.accmap = (u_int32_t)ulong_val;
155936285Sbrian    } else {
156036285Sbrian      err = "No accmap specified\n";
156136285Sbrian      log_Printf(LogWARN, err);
156236285Sbrian    }
156336285Sbrian    break;
156437210Sbrian
156536285Sbrian  case VAR_MODE:
156636285Sbrian    mode = Nam2mode(argp);
156736285Sbrian    if (mode == PHYS_NONE || mode == PHYS_ALL) {
156836285Sbrian      log_Printf(LogWARN, "%s: Invalid mode\n", argp);
156936285Sbrian      return -1;
157036285Sbrian    }
157136285Sbrian    bundle_SetMode(arg->bundle, cx, mode);
157236285Sbrian    break;
157337210Sbrian
157436285Sbrian  case VAR_MRRU:
157540622Sbrian    switch (bundle_Phase(arg->bundle)) {
157640622Sbrian      case PHASE_DEAD:
157740622Sbrian        break;
157840622Sbrian      case PHASE_ESTABLISH:
157940622Sbrian        /* Make sure none of our links are DATALINK_LCP or greater */
158040622Sbrian        if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) {
158140622Sbrian          log_Printf(LogWARN, "mrru: Only changable before LCP negotiations\n");
158240622Sbrian          return 1;
158340622Sbrian        }
158440622Sbrian        break;
158540622Sbrian      default:
158640622Sbrian        log_Printf(LogWARN, "mrru: Only changable at phase DEAD/ESTABLISH\n");
158740622Sbrian        return 1;
158829696Sbrian    }
158937210Sbrian    long_val = atol(argp);
159037210Sbrian    if (long_val && long_val < MIN_MRU) {
159137210Sbrian      log_Printf(LogWARN, "MRRU %ld: too small - min %d\n", long_val, MIN_MRU);
159237210Sbrian      return 1;
159337210Sbrian    } else if (long_val > MAX_MRU) {
159437210Sbrian      log_Printf(LogWARN, "MRRU %ld: too big - max %d\n", long_val, MAX_MRU);
159537210Sbrian      return 1;
159637210Sbrian    } else
159737210Sbrian      arg->bundle->ncp.mp.cfg.mrru = long_val;
159828679Sbrian    break;
159937210Sbrian
160036285Sbrian  case VAR_MRU:
160137210Sbrian    long_val = atol(argp);
160237210Sbrian    if (long_val == 0)
160337210Sbrian      l->lcp.cfg.mru = DEF_MRU;
160437210Sbrian    else if (long_val < MIN_MRU) {
160537210Sbrian      log_Printf(LogWARN, "MRU %ld: too small - min %d\n", long_val, MIN_MRU);
160637210Sbrian      return 1;
160737210Sbrian    } else if (long_val > MAX_MRU) {
160837210Sbrian      log_Printf(LogWARN, "MRU %ld: too big - max %d\n", long_val, MAX_MRU);
160937210Sbrian      return 1;
161037210Sbrian    } else
161137210Sbrian      l->lcp.cfg.mru = long_val;
161228679Sbrian    break;
161337210Sbrian
161436285Sbrian  case VAR_MTU:
161537210Sbrian    long_val = atol(argp);
161637210Sbrian    if (long_val && long_val < MIN_MTU) {
161737210Sbrian      log_Printf(LogWARN, "MTU %ld: too small - min %d\n", long_val, MIN_MTU);
161837210Sbrian      return 1;
161937210Sbrian    } else if (long_val > MAX_MTU) {
162037210Sbrian      log_Printf(LogWARN, "MTU %ld: too big - max %d\n", long_val, MAX_MTU);
162137210Sbrian      return 1;
162237210Sbrian    } else
162337210Sbrian      arg->bundle->cfg.mtu = long_val;
162436285Sbrian    break;
162537210Sbrian
162636285Sbrian  case VAR_OPENMODE:
162736285Sbrian    if (strcasecmp(argp, "active") == 0)
162836285Sbrian      cx->physical->link.lcp.cfg.openmode = arg->argc > arg->argn+1 ?
162936285Sbrian        atoi(arg->argv[arg->argn+1]) : 1;
163036285Sbrian    else if (strcasecmp(argp, "passive") == 0)
163136285Sbrian      cx->physical->link.lcp.cfg.openmode = OPEN_PASSIVE;
163236285Sbrian    else {
163336285Sbrian      err = "%s: Invalid openmode\n";
163436285Sbrian      log_Printf(LogWARN, err, argp);
163536285Sbrian    }
163636285Sbrian    break;
163737210Sbrian
163828679Sbrian  case VAR_PHONE:
163936285Sbrian    strncpy(cx->cfg.phone.list, argp, sizeof cx->cfg.phone.list - 1);
164036285Sbrian    cx->cfg.phone.list[sizeof cx->cfg.phone.list - 1] = '\0';
164138174Sbrian    cx->phone.alt = cx->phone.next = NULL;
164228679Sbrian    break;
164337210Sbrian
164428679Sbrian  case VAR_HANGUP:
164536285Sbrian    strncpy(cx->cfg.script.hangup, argp, sizeof cx->cfg.script.hangup - 1);
164636285Sbrian    cx->cfg.script.hangup[sizeof cx->cfg.script.hangup - 1] = '\0';
164728679Sbrian    break;
164837210Sbrian
164961534Sbrian  case VAR_IFQUEUE:
165061534Sbrian    long_val = atol(argp);
165161534Sbrian    arg->bundle->cfg.ifqueue = long_val < 0 ? 0 : long_val;
165261534Sbrian    break;
165361534Sbrian
165452488Sbrian  case VAR_LOGOUT:
165552488Sbrian    strncpy(cx->cfg.script.logout, argp, sizeof cx->cfg.script.logout - 1);
165652488Sbrian    cx->cfg.script.logout[sizeof cx->cfg.script.logout - 1] = '\0';
165752488Sbrian    break;
165852488Sbrian
165936285Sbrian  case VAR_IDLETIMEOUT:
166049978Sbrian    if (arg->argc > arg->argn+2)
166136285Sbrian      err = "Too many idle timeout values\n";
166249978Sbrian    else if (arg->argc == arg->argn)
166349978Sbrian      err = "Too few idle timeout values\n";
166449978Sbrian    else {
166549978Sbrian      int timeout, min;
166649978Sbrian
166749978Sbrian      timeout = atoi(argp);
166849978Sbrian      min = arg->argc == arg->argn + 2 ? atoi(arg->argv[arg->argn + 1]) : -1;
166949978Sbrian      bundle_SetIdleTimer(arg->bundle, timeout, min);
167049978Sbrian    }
167136285Sbrian    if (err)
167236285Sbrian      log_Printf(LogWARN, err);
167329549Sbrian    break;
167437210Sbrian
167536285Sbrian  case VAR_LQRPERIOD:
167637210Sbrian    long_val = atol(argp);
167737210Sbrian    if (long_val < MIN_LQRPERIOD) {
167837210Sbrian      log_Printf(LogWARN, "%ld: Invalid lqr period - min %d\n",
167937210Sbrian                 long_val, MIN_LQRPERIOD);
168037210Sbrian      return 1;
168136285Sbrian    } else
168237210Sbrian      l->lcp.cfg.lqrperiod = long_val;
168336285Sbrian    break;
168437210Sbrian
168536285Sbrian  case VAR_LCPRETRY:
168644305Sbrian    return SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
168744305Sbrian                    &cx->physical->link.lcp.cfg.fsm.timeout,
168844305Sbrian                    &cx->physical->link.lcp.cfg.fsm.maxreq,
168944305Sbrian                    &cx->physical->link.lcp.cfg.fsm.maxtrm, DEF_FSMTRIES);
169036285Sbrian    break;
169137210Sbrian
169236285Sbrian  case VAR_CHAPRETRY:
169344305Sbrian    return SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
169444305Sbrian                    &cx->chap.auth.cfg.fsm.timeout,
169544305Sbrian                    &cx->chap.auth.cfg.fsm.maxreq, NULL, DEF_FSMAUTHTRIES);
169636285Sbrian    break;
169737210Sbrian
169836285Sbrian  case VAR_PAPRETRY:
169944305Sbrian    return SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
170044305Sbrian                    &cx->pap.cfg.fsm.timeout, &cx->pap.cfg.fsm.maxreq,
170144305Sbrian                    NULL, DEF_FSMAUTHTRIES);
170236285Sbrian    break;
170337210Sbrian
170436285Sbrian  case VAR_CCPRETRY:
170544305Sbrian    return SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
170644305Sbrian                    &l->ccp.cfg.fsm.timeout, &l->ccp.cfg.fsm.maxreq,
170744305Sbrian                    &l->ccp.cfg.fsm.maxtrm, DEF_FSMTRIES);
170836285Sbrian    break;
170937210Sbrian
171036285Sbrian  case VAR_IPCPRETRY:
171144305Sbrian    return SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
171244305Sbrian                    &arg->bundle->ncp.ipcp.cfg.fsm.timeout,
171344305Sbrian                    &arg->bundle->ncp.ipcp.cfg.fsm.maxreq,
171444305Sbrian                    &arg->bundle->ncp.ipcp.cfg.fsm.maxtrm, DEF_FSMTRIES);
171536285Sbrian    break;
171637210Sbrian
171736285Sbrian  case VAR_NBNS:
171836285Sbrian  case VAR_DNS:
171958044Sbrian    if (param == VAR_DNS) {
172036285Sbrian      addr = arg->bundle->ncp.ipcp.cfg.ns.dns;
172158044Sbrian      addr[0].s_addr = addr[1].s_addr = INADDR_NONE;
172258044Sbrian    } else {
172336285Sbrian      addr = arg->bundle->ncp.ipcp.cfg.ns.nbns;
172458044Sbrian      addr[0].s_addr = addr[1].s_addr = INADDR_ANY;
172558044Sbrian    }
172636285Sbrian
172736285Sbrian    if (arg->argc > arg->argn) {
172843313Sbrian      ParseAddr(&arg->bundle->ncp.ipcp, arg->argv[arg->argn],
172936285Sbrian                addr, &dummyaddr, &dummyint);
173036285Sbrian      if (arg->argc > arg->argn+1)
173143313Sbrian        ParseAddr(&arg->bundle->ncp.ipcp, arg->argv[arg->argn + 1],
173236285Sbrian                  addr + 1, &dummyaddr, &dummyint);
173336285Sbrian
173458044Sbrian      if (addr[0].s_addr == INADDR_ANY) {
173536285Sbrian        addr[0].s_addr = addr[1].s_addr;
173658044Sbrian        addr[1].s_addr = INADDR_ANY;
173758044Sbrian      }
173858044Sbrian      if (addr[0].s_addr == INADDR_NONE) {
173958044Sbrian        addr[0].s_addr = addr[1].s_addr;
174058044Sbrian        addr[1].s_addr = INADDR_NONE;
174158044Sbrian      }
174236285Sbrian    }
174336285Sbrian    break;
174438174Sbrian
174538174Sbrian  case VAR_CALLBACK:
174638174Sbrian    cx->cfg.callback.opmask = 0;
174738174Sbrian    for (dummyint = arg->argn; dummyint < arg->argc; dummyint++) {
174838174Sbrian      if (!strcasecmp(arg->argv[dummyint], "auth"))
174938174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_AUTH);
175038174Sbrian      else if (!strcasecmp(arg->argv[dummyint], "cbcp"))
175138174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_CBCP);
175238174Sbrian      else if (!strcasecmp(arg->argv[dummyint], "e.164")) {
175338174Sbrian        if (dummyint == arg->argc - 1)
175438174Sbrian          log_Printf(LogWARN, "No E.164 arg (E.164 ignored) !\n");
175538174Sbrian        else {
175638174Sbrian          cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_E164);
175738174Sbrian          strncpy(cx->cfg.callback.msg, arg->argv[++dummyint],
175838174Sbrian                  sizeof cx->cfg.callback.msg - 1);
175938174Sbrian          cx->cfg.callback.msg[sizeof cx->cfg.callback.msg - 1] = '\0';
176038174Sbrian        }
176138174Sbrian      } else if (!strcasecmp(arg->argv[dummyint], "none"))
176238174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_NONE);
176338174Sbrian      else
176438174Sbrian        return -1;
176538174Sbrian    }
176638174Sbrian    if (cx->cfg.callback.opmask == CALLBACK_BIT(CALLBACK_NONE))
176738174Sbrian      cx->cfg.callback.opmask = 0;
176838174Sbrian    break;
176938174Sbrian
177038174Sbrian  case VAR_CBCP:
177138174Sbrian    cx->cfg.cbcp.delay = 0;
177238174Sbrian    *cx->cfg.cbcp.phone = '\0';
177338174Sbrian    cx->cfg.cbcp.fsmretry = DEF_FSMRETRY;
177438174Sbrian    if (arg->argc > arg->argn) {
177538174Sbrian      strncpy(cx->cfg.cbcp.phone, arg->argv[arg->argn],
177638174Sbrian              sizeof cx->cfg.cbcp.phone - 1);
177738174Sbrian      cx->cfg.cbcp.phone[sizeof cx->cfg.cbcp.phone - 1] = '\0';
177838174Sbrian      if (arg->argc > arg->argn + 1) {
177938174Sbrian        cx->cfg.cbcp.delay = atoi(arg->argv[arg->argn + 1]);
178038174Sbrian        if (arg->argc > arg->argn + 2) {
178138174Sbrian          long_val = atol(arg->argv[arg->argn + 2]);
178238174Sbrian          if (long_val < MIN_FSMRETRY)
178338174Sbrian            log_Printf(LogWARN, "%ld: Invalid CBCP FSM retry period - min %d\n",
178438174Sbrian                       long_val, MIN_FSMRETRY);
178538174Sbrian          else
178638174Sbrian            cx->cfg.cbcp.fsmretry = long_val;
178738174Sbrian        }
178838174Sbrian      }
178938174Sbrian    }
179038174Sbrian    break;
179138544Sbrian
179238544Sbrian  case VAR_CHOKED:
179338544Sbrian    arg->bundle->cfg.choked.timeout = atoi(argp);
179438544Sbrian    if (arg->bundle->cfg.choked.timeout <= 0)
179538544Sbrian      arg->bundle->cfg.choked.timeout = CHOKED_TIMEOUT;
179638544Sbrian    break;
179740665Sbrian
179840665Sbrian  case VAR_SENDPIPE:
179940665Sbrian    long_val = atol(argp);
180040665Sbrian    arg->bundle->ncp.ipcp.cfg.sendpipe = long_val;
180140665Sbrian    break;
180240665Sbrian
180340665Sbrian  case VAR_RECVPIPE:
180440665Sbrian    long_val = atol(argp);
180540665Sbrian    arg->bundle->ncp.ipcp.cfg.recvpipe = long_val;
180640665Sbrian    break;
180743313Sbrian
180843313Sbrian#ifndef NORADIUS
180943313Sbrian  case VAR_RADIUS:
181043313Sbrian    if (!*argp)
181143313Sbrian      *arg->bundle->radius.cfg.file = '\0';
181243313Sbrian    else if (access(argp, R_OK)) {
181343313Sbrian      log_Printf(LogWARN, "%s: %s\n", argp, strerror(errno));
181443313Sbrian      return 1;
181543313Sbrian    } else {
181643313Sbrian      strncpy(arg->bundle->radius.cfg.file, argp,
181743313Sbrian              sizeof arg->bundle->radius.cfg.file - 1);
181843313Sbrian      arg->bundle->radius.cfg.file
181943313Sbrian        [sizeof arg->bundle->radius.cfg.file - 1] = '\0';
182043313Sbrian    }
182143313Sbrian    break;
182243313Sbrian#endif
182344073Sbrian
182444073Sbrian  case VAR_CD:
182544073Sbrian    if (*argp) {
182651699Sbrian      if (strcasecmp(argp, "off")) {
182751699Sbrian        long_val = atol(argp);
182851699Sbrian        if (long_val < 0)
182951699Sbrian          long_val = 0;
183051699Sbrian        cx->physical->cfg.cd.delay = long_val;
183151699Sbrian        cx->physical->cfg.cd.necessity = argp[strlen(argp)-1] == '!' ?
183251699Sbrian          CD_REQUIRED : CD_VARIABLE;
183351699Sbrian      } else
183451699Sbrian        cx->physical->cfg.cd.necessity = CD_NOTREQUIRED;
183544073Sbrian    } else {
183653733Sbrian      cx->physical->cfg.cd.delay = 0;
183753733Sbrian      cx->physical->cfg.cd.necessity = CD_DEFAULT;
183844073Sbrian    }
183944073Sbrian    break;
184036285Sbrian
184146686Sbrian  case VAR_PARITY:
184246686Sbrian    if (arg->argc == arg->argn + 1)
184346686Sbrian      return physical_SetParity(arg->cx->physical, argp);
184446686Sbrian    else {
184546686Sbrian      err = "Parity value must be odd, even or none\n";
184646686Sbrian      log_Printf(LogWARN, err);
184746686Sbrian    }
184846686Sbrian    break;
18496059Samurai
185046686Sbrian  case VAR_CRTSCTS:
185146686Sbrian    if (strcasecmp(argp, "on") == 0)
185236285Sbrian      physical_SetRtsCts(arg->cx->physical, 1);
185346686Sbrian    else if (strcasecmp(argp, "off") == 0)
185436285Sbrian      physical_SetRtsCts(arg->cx->physical, 0);
185546686Sbrian    else {
185646686Sbrian      err = "RTS/CTS value must be on or off\n";
185746686Sbrian      log_Printf(LogWARN, err);
185846686Sbrian    }
185946686Sbrian    break;
186050867Sbrian
186150867Sbrian  case VAR_URGENTPORTS:
186251048Sbrian    if (arg->argn == arg->argc) {
186361430Sbrian      ipcp_SetUrgentTOS(&arg->bundle->ncp.ipcp);
186451048Sbrian      ipcp_ClearUrgentTcpPorts(&arg->bundle->ncp.ipcp);
186551048Sbrian      ipcp_ClearUrgentUdpPorts(&arg->bundle->ncp.ipcp);
186651048Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "udp")) {
186761430Sbrian      ipcp_SetUrgentTOS(&arg->bundle->ncp.ipcp);
186851048Sbrian      if (arg->argn == arg->argc - 1)
186951048Sbrian        ipcp_ClearUrgentUdpPorts(&arg->bundle->ncp.ipcp);
187051048Sbrian      else for (f = arg->argn + 1; f < arg->argc; f++)
187151048Sbrian        if (*arg->argv[f] == '+')
187251048Sbrian          ipcp_AddUrgentUdpPort(&arg->bundle->ncp.ipcp, atoi(arg->argv[f] + 1));
187351048Sbrian        else if (*arg->argv[f] == '-')
187451048Sbrian          ipcp_RemoveUrgentUdpPort(&arg->bundle->ncp.ipcp,
187551048Sbrian                                   atoi(arg->argv[f] + 1));
187651048Sbrian        else {
187751048Sbrian          if (f == arg->argn)
187851048Sbrian            ipcp_ClearUrgentUdpPorts(&arg->bundle->ncp.ipcp);
187951048Sbrian          ipcp_AddUrgentUdpPort(&arg->bundle->ncp.ipcp, atoi(arg->argv[f]));
188051048Sbrian        }
188161430Sbrian    } else if (arg->argn == arg->argc - 1 &&
188261430Sbrian               !strcasecmp(arg->argv[arg->argn], "none")) {
188361430Sbrian      ipcp_ClearUrgentTcpPorts(&arg->bundle->ncp.ipcp);
188461430Sbrian      ipcp_ClearUrgentUdpPorts(&arg->bundle->ncp.ipcp);
188561430Sbrian      ipcp_ClearUrgentTOS(&arg->bundle->ncp.ipcp);
188651048Sbrian    } else {
188761430Sbrian      ipcp_SetUrgentTOS(&arg->bundle->ncp.ipcp);
188851048Sbrian      first = arg->argn;
188951048Sbrian      if (!strcasecmp(arg->argv[first], "tcp") && ++first == arg->argc)
189051048Sbrian        ipcp_ClearUrgentTcpPorts(&arg->bundle->ncp.ipcp);
189151048Sbrian
189251048Sbrian      for (f = first; f < arg->argc; f++)
189351048Sbrian        if (*arg->argv[f] == '+')
189451048Sbrian          ipcp_AddUrgentTcpPort(&arg->bundle->ncp.ipcp, atoi(arg->argv[f] + 1));
189551048Sbrian        else if (*arg->argv[f] == '-')
189651048Sbrian          ipcp_RemoveUrgentTcpPort(&arg->bundle->ncp.ipcp,
189751048Sbrian                                   atoi(arg->argv[f] + 1));
189851048Sbrian        else {
189951048Sbrian          if (f == first)
190051048Sbrian            ipcp_ClearUrgentTcpPorts(&arg->bundle->ncp.ipcp);
190151048Sbrian          ipcp_AddUrgentTcpPort(&arg->bundle->ncp.ipcp, atoi(arg->argv[f]));
190251048Sbrian        }
190351048Sbrian    }
190450867Sbrian    break;
190520812Sjkh  }
190646686Sbrian
190746686Sbrian  return err ? 1 : 0;
190820812Sjkh}
190920812Sjkh
191030715Sbrianstatic struct cmdtab const SetCommands[] = {
191136285Sbrian  {"accmap", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
191236285Sbrian  "accmap value", "set accmap hex-value", (const void *)VAR_ACCMAP},
191328679Sbrian  {"authkey", "key", SetVariable, LOCAL_AUTH,
191436285Sbrian  "authentication key", "set authkey|key key", (const void *)VAR_AUTHKEY},
191528679Sbrian  {"authname", NULL, SetVariable, LOCAL_AUTH,
191636285Sbrian  "authentication name", "set authname name", (const void *)VAR_AUTHNAME},
191736285Sbrian  {"autoload", NULL, SetVariable, LOCAL_AUTH,
191836285Sbrian  "auto link [de]activation", "set autoload maxtime maxload mintime minload",
191936285Sbrian  (const void *)VAR_AUTOLOAD},
192050867Sbrian  {"bandwidth", NULL, mp_SetDatalinkBandwidth, LOCAL_AUTH | LOCAL_CX,
192150867Sbrian  "datalink bandwidth", "set bandwidth value"},
192238174Sbrian  {"callback", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
192338174Sbrian  "callback control", "set callback [none|auth|cbcp|"
192438174Sbrian  "E.164 *|number[,number]...]...", (const void *)VAR_CALLBACK},
192538174Sbrian  {"cbcp", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
192638174Sbrian  "CBCP control", "set cbcp [*|phone[,phone...] [delay [timeout]]]",
192738174Sbrian  (const void *)VAR_CBCP},
192844305Sbrian  {"ccpretry", "ccpretries", SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
192944305Sbrian   "CCP retries", "set ccpretry value [attempts]", (const void *)VAR_CCPRETRY},
193044073Sbrian  {"cd", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "Carrier delay requirement",
193144073Sbrian   "set cd value[!]", (const void *)VAR_CD},
193244305Sbrian  {"chapretry", "chapretries", SetVariable, LOCAL_AUTH | LOCAL_CX,
193344305Sbrian   "CHAP retries", "set chapretry value [attempts]",
193444305Sbrian   (const void *)VAR_CHAPRETRY},
193538544Sbrian  {"choked", NULL, SetVariable, LOCAL_AUTH,
193638544Sbrian  "choked timeout", "set choked [secs]", (const void *)VAR_CHOKED},
193746686Sbrian  {"ctsrts", "crtscts", SetVariable, LOCAL_AUTH | LOCAL_CX,
193846686Sbrian   "Use hardware flow control", "set ctsrts [on|off]",
193946686Sbrian   (const char *)VAR_CRTSCTS},
194036285Sbrian  {"deflate", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
194136285Sbrian  "deflate window sizes", "set deflate out-winsize in-winsize",
194236285Sbrian  (const void *) VAR_WINSIZE},
194336285Sbrian  {"device", "line", SetVariable, LOCAL_AUTH | LOCAL_CX,
194446686Sbrian  "physical device name", "set device|line device-name[,device-name]",
194536285Sbrian  (const void *) VAR_DEVICE},
194636285Sbrian  {"dial", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
194736285Sbrian  "dialing script", "set dial chat-script", (const void *) VAR_DIAL},
194836285Sbrian  {"dns", NULL, SetVariable, LOCAL_AUTH, "Domain Name Server",
194936285Sbrian  "set dns pri-addr [sec-addr]", (const void *)VAR_DNS},
195036285Sbrian  {"enddisc", NULL, mp_SetEnddisc, LOCAL_AUTH,
195136285Sbrian  "Endpoint Discriminator", "set enddisc [IP|magic|label|psn value]"},
195236285Sbrian  {"escape", NULL, SetEscape, LOCAL_AUTH | LOCAL_CX,
195336285Sbrian  "escape characters", "set escape hex-digit ..."},
195436285Sbrian  {"filter", NULL, filter_Set, LOCAL_AUTH,
195536285Sbrian  "packet filters", "set filter alive|dial|in|out rule-no permit|deny "
195649388Sbrian  "[src_addr[/width]] [dst_addr[/width]] [tcp|udp|icmp|ospf|igmp "
195748142Sbrian  "[src [lt|eq|gt port]] [dst [lt|eq|gt port]] [estab] [syn] [finrst]]"},
195836285Sbrian  {"hangup", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
195936285Sbrian  "hangup script", "set hangup chat-script", (const void *) VAR_HANGUP},
196036285Sbrian  {"ifaddr", NULL, SetInterfaceAddr, LOCAL_AUTH, "destination address",
196131343Sbrian  "set ifaddr [src-addr [dst-addr [netmask [trg-addr]]]]"},
196261534Sbrian  {"ifqueue", NULL, SetVariable, LOCAL_AUTH, "interface queue",
196361534Sbrian  "set ifqueue packets", (const void *)VAR_IFQUEUE},
196444305Sbrian  {"ipcpretry", "ipcpretries", SetVariable, LOCAL_AUTH, "IPCP retries",
196544305Sbrian   "set ipcpretry value [attempts]", (const void *)VAR_IPCPRETRY},
196644305Sbrian  {"lcpretry", "lcpretries", SetVariable, LOCAL_AUTH | LOCAL_CX, "LCP retries",
196744305Sbrian   "set lcpretry value [attempts]", (const void *)VAR_LCPRETRY},
196836712Sbrian  {"log", NULL, log_SetLevel, LOCAL_AUTH, "log level",
196958033Sbrian  "set log [local] [+|-]async|cbcp|ccp|chat|command|connect|debug|dns|hdlc|"
197058033Sbrian  "id0|ipcp|lcp|lqm|phase|physical|sync|tcp/ip|timer|tun..."},
197136285Sbrian  {"login", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
197236285Sbrian  "login script", "set login chat-script", (const void *) VAR_LOGIN},
197352488Sbrian  {"logout", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
197452488Sbrian  "logout script", "set logout chat-script", (const void *) VAR_LOGOUT},
197536285Sbrian  {"lqrperiod", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
197636285Sbrian  "LQR period", "set lqrperiod value", (const void *)VAR_LQRPERIOD},
197736285Sbrian  {"mode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "mode value",
197836285Sbrian  "set mode interactive|auto|ddial|background", (const void *)VAR_MODE},
197936285Sbrian  {"mrru", NULL, SetVariable, LOCAL_AUTH, "MRRU value",
198036285Sbrian  "set mrru value", (const void *)VAR_MRRU},
198136285Sbrian  {"mru", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
198236285Sbrian  "MRU value", "set mru value", (const void *)VAR_MRU},
198336285Sbrian  {"mtu", NULL, SetVariable, LOCAL_AUTH,
198436285Sbrian  "interface MTU value", "set mtu value", (const void *)VAR_MTU},
198536285Sbrian  {"nbns", NULL, SetVariable, LOCAL_AUTH, "NetBIOS Name Server",
198636285Sbrian  "set nbns pri-addr [sec-addr]", (const void *)VAR_NBNS},
198736285Sbrian  {"openmode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "open mode",
198836285Sbrian  "set openmode active|passive [secs]", (const void *)VAR_OPENMODE},
198944305Sbrian  {"papretry", "papretries", SetVariable, LOCAL_AUTH | LOCAL_CX, "PAP retries",
199044305Sbrian   "set papretry value [attempts]", (const void *)VAR_PAPRETRY},
199146686Sbrian  {"parity", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "serial parity",
199246686Sbrian   "set parity [odd|even|none]", (const void *)VAR_PARITY},
199336285Sbrian  {"phone", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "telephone number(s)",
199436285Sbrian  "set phone phone1[:phone2[...]]", (const void *)VAR_PHONE},
199540679Sbrian  {"proctitle", "title", SetProcTitle, LOCAL_AUTH,
199640679Sbrian  "Process title", "set proctitle [value]"},
199743313Sbrian#ifndef NORADIUS
199843313Sbrian  {"radius", NULL, SetVariable, LOCAL_AUTH,
199943313Sbrian  "RADIUS Config", "set radius cfgfile", (const void *)VAR_RADIUS},
200043313Sbrian#endif
200136285Sbrian  {"reconnect", NULL, datalink_SetReconnect, LOCAL_AUTH | LOCAL_CX,
200236285Sbrian  "Reconnect timeout", "set reconnect value ntries"},
200340665Sbrian  {"recvpipe", NULL, SetVariable, LOCAL_AUTH,
200440665Sbrian  "RECVPIPE value", "set recvpipe value", (const void *)VAR_RECVPIPE},
200536285Sbrian  {"redial", NULL, datalink_SetRedial, LOCAL_AUTH | LOCAL_CX,
200644468Sbrian  "Redial timeout", "set redial secs[+inc[-incmax]][.next] [attempts]"},
200740665Sbrian  {"sendpipe", NULL, SetVariable, LOCAL_AUTH,
200840665Sbrian  "SENDPIPE value", "set sendpipe value", (const void *)VAR_SENDPIPE},
200928679Sbrian  {"server", "socket", SetServer, LOCAL_AUTH,
201036774Sbrian  "server port", "set server|socket TcpPort|LocalName|none password [mask]"},
201136285Sbrian  {"speed", NULL, SetModemSpeed, LOCAL_AUTH | LOCAL_CX,
201246686Sbrian  "physical speed", "set speed value|sync"},
201336285Sbrian  {"stopped", NULL, SetStoppedTimeout, LOCAL_AUTH | LOCAL_CX,
201436285Sbrian  "STOPPED timeouts", "set stopped [LCPseconds [CCPseconds]]"},
201536285Sbrian  {"timeout", NULL, SetVariable, LOCAL_AUTH, "Idle timeout",
201636285Sbrian  "set timeout idletime", (const void *)VAR_IDLETIMEOUT},
201751048Sbrian  {"urgent", NULL, SetVariable, LOCAL_AUTH, "urgent ports",
201851048Sbrian  "set urgent [tcp|udp] [+|-]port...", (const void *)VAR_URGENTPORTS},
201936285Sbrian  {"vj", NULL, ipcp_vjset, LOCAL_AUTH,
202036285Sbrian  "vj values", "set vj slots|slotcomp [value]"},
202128679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
202231343Sbrian  "Display this message", "set help|? [command]", SetCommands},
202328679Sbrian  {NULL, NULL, NULL},
20246059Samurai};
20256059Samurai
20266059Samuraistatic int
202731343SbrianSetCommand(struct cmdargs const *arg)
20286059Samurai{
202936285Sbrian  if (arg->argc > arg->argn)
203036285Sbrian    FindExec(arg->bundle, SetCommands, arg->argc, arg->argn, arg->argv,
203136285Sbrian             arg->prompt, arg->cx);
203236285Sbrian  else if (arg->prompt)
203336285Sbrian    prompt_Printf(arg->prompt, "Use `set ?' to get a list or `set ? <var>' for"
203458044Sbrian	          " syntax help.\n");
20356059Samurai  else
203636285Sbrian    log_Printf(LogWARN, "set command must have arguments\n");
203726516Sbrian
203826516Sbrian  return 0;
20396059Samurai}
20406059Samurai
20416059Samuraistatic int
204231343SbrianAddCommand(struct cmdargs const *arg)
20436059Samurai{
20446059Samurai  struct in_addr dest, gateway, netmask;
204536285Sbrian  int gw, addrs;
20466059Samurai
204736285Sbrian  if (arg->argc != arg->argn+3 && arg->argc != arg->argn+2)
204831598Sbrian    return -1;
204931598Sbrian
205036285Sbrian  addrs = 0;
205136285Sbrian  if (arg->argc == arg->argn+2) {
205236285Sbrian    if (!strcasecmp(arg->argv[arg->argn], "default"))
205336285Sbrian      dest.s_addr = netmask.s_addr = INADDR_ANY;
205431598Sbrian    else {
205536285Sbrian      int width;
205636285Sbrian
205743313Sbrian      if (!ParseAddr(&arg->bundle->ncp.ipcp, arg->argv[arg->argn],
205836285Sbrian	             &dest, &netmask, &width))
205936285Sbrian        return -1;
206036285Sbrian      if (!strncasecmp(arg->argv[arg->argn], "MYADDR", 6))
206136285Sbrian        addrs = ROUTE_DSTMYADDR;
206236285Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "HISADDR", 7))
206336285Sbrian        addrs = ROUTE_DSTHISADDR;
206458044Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "DNS0", 4))
206558044Sbrian        addrs = ROUTE_DSTDNS0;
206658044Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "DNS1", 4))
206758044Sbrian        addrs = ROUTE_DSTDNS1;
206831598Sbrian    }
206936285Sbrian    gw = 1;
207034536Sbrian  } else {
207136285Sbrian    if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
207236285Sbrian      addrs = ROUTE_DSTMYADDR;
207336285Sbrian      dest = arg->bundle->ncp.ipcp.my_ip;
207436285Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
207536285Sbrian      addrs = ROUTE_DSTHISADDR;
207636285Sbrian      dest = arg->bundle->ncp.ipcp.peer_ip;
207758044Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "DNS0") == 0) {
207858044Sbrian      addrs = ROUTE_DSTDNS0;
207958044Sbrian      dest = arg->bundle->ncp.ipcp.ns.dns[0];
208058044Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "DNS1") == 0) {
208158044Sbrian      addrs = ROUTE_DSTDNS1;
208258044Sbrian      dest = arg->bundle->ncp.ipcp.ns.dns[1];
208336285Sbrian    } else
208436285Sbrian      dest = GetIpAddr(arg->argv[arg->argn]);
208536285Sbrian    netmask = GetIpAddr(arg->argv[arg->argn+1]);
208631598Sbrian    gw = 2;
20876059Samurai  }
208836285Sbrian
208936285Sbrian  if (strcasecmp(arg->argv[arg->argn+gw], "HISADDR") == 0) {
209036285Sbrian    gateway = arg->bundle->ncp.ipcp.peer_ip;
209136285Sbrian    addrs |= ROUTE_GWHISADDR;
209240561Sbrian  } else
209336285Sbrian    gateway = GetIpAddr(arg->argv[arg->argn+gw]);
209436285Sbrian
209536285Sbrian  if (bundle_SetRoute(arg->bundle, RTM_ADD, dest, gateway, netmask,
209643313Sbrian                  arg->cmd->args ? 1 : 0, (addrs & ROUTE_GWHISADDR) ? 1 : 0)
209743313Sbrian      && addrs != ROUTE_STATIC)
209836285Sbrian    route_Add(&arg->bundle->ncp.ipcp.route, addrs, dest, netmask, gateway);
209936285Sbrian
210031598Sbrian  return 0;
21016059Samurai}
21026059Samurai
21036059Samuraistatic int
210431343SbrianDeleteCommand(struct cmdargs const *arg)
21056059Samurai{
210631598Sbrian  struct in_addr dest, none;
210736285Sbrian  int addrs;
21086059Samurai
210936285Sbrian  if (arg->argc == arg->argn+1) {
211036285Sbrian    if(strcasecmp(arg->argv[arg->argn], "all") == 0) {
211136285Sbrian      route_IfDelete(arg->bundle, 0);
211236285Sbrian      route_DeleteAll(&arg->bundle->ncp.ipcp.route);
211336285Sbrian    } else {
211436285Sbrian      addrs = 0;
211536285Sbrian      if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
211636285Sbrian        dest = arg->bundle->ncp.ipcp.my_ip;
211736285Sbrian        addrs = ROUTE_DSTMYADDR;
211836285Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
211936285Sbrian        dest = arg->bundle->ncp.ipcp.peer_ip;
212036285Sbrian        addrs = ROUTE_DSTHISADDR;
212158044Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "DNS0") == 0) {
212258044Sbrian        dest = arg->bundle->ncp.ipcp.ns.dns[0];
212358044Sbrian        addrs = ROUTE_DSTDNS0;
212458044Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "DNS1") == 0) {
212558044Sbrian        dest = arg->bundle->ncp.ipcp.ns.dns[1];
212658044Sbrian        addrs = ROUTE_DSTDNS1;
212736285Sbrian      } else {
212844279Sbrian        dest = GetIpAddr(arg->argv[arg->argn]);
212944279Sbrian        if (dest.s_addr == INADDR_NONE) {
213044279Sbrian          log_Printf(LogWARN, "%s: Invalid IP address\n", arg->argv[arg->argn]);
213144279Sbrian          return -1;
213244279Sbrian        }
213336285Sbrian        addrs = ROUTE_STATIC;
213436285Sbrian      }
213531598Sbrian      none.s_addr = INADDR_ANY;
213636285Sbrian      bundle_SetRoute(arg->bundle, RTM_DELETE, dest, none, none,
213737927Sbrian                      arg->cmd->args ? 1 : 0, 0);
213836285Sbrian      route_Delete(&arg->bundle->ncp.ipcp.route, addrs, dest);
213931598Sbrian    }
214034536Sbrian  } else
214126516Sbrian    return -1;
214226516Sbrian
214326516Sbrian  return 0;
21446059Samurai}
21456059Samurai
214650059Sbrian#ifndef NONAT
214726031Sbrianstatic int
214858867SbrianNatEnable(struct cmdargs const *arg)
214926031Sbrian{
215036285Sbrian  if (arg->argc == arg->argn+1) {
215136285Sbrian    if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
215250059Sbrian      if (!arg->bundle->NatEnabled) {
215346686Sbrian        if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED)
215446686Sbrian          PacketAliasSetAddress(arg->bundle->ncp.ipcp.my_ip);
215550059Sbrian        arg->bundle->NatEnabled = 1;
215646686Sbrian      }
215737191Sbrian      return 0;
215836285Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "no") == 0) {
215950059Sbrian      arg->bundle->NatEnabled = 0;
216040561Sbrian      arg->bundle->cfg.opt &= ~OPT_IFACEALIAS;
216140561Sbrian      /* Don't iface_Clear() - there may be manually configured addresses */
216226516Sbrian      return 0;
216326142Sbrian    }
216435449Sbrian  }
216536285Sbrian
216626516Sbrian  return -1;
216726031Sbrian}
216826031Sbrian
216926031Sbrian
217026031Sbrianstatic int
217158867SbrianNatOption(struct cmdargs const *arg)
217226031Sbrian{
217338559Sbrian  long param = (long)arg->cmd->args;
217438559Sbrian
217536285Sbrian  if (arg->argc == arg->argn+1) {
217636285Sbrian    if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
217750059Sbrian      if (arg->bundle->NatEnabled) {
217837191Sbrian	PacketAliasSetMode(param, param);
217928679Sbrian	return 0;
218028679Sbrian      }
218150059Sbrian      log_Printf(LogWARN, "nat not enabled\n");
218236285Sbrian    } else if (strcmp(arg->argv[arg->argn], "no") == 0) {
218350059Sbrian      if (arg->bundle->NatEnabled) {
218437191Sbrian	PacketAliasSetMode(0, param);
218528679Sbrian	return 0;
218628679Sbrian      }
218750059Sbrian      log_Printf(LogWARN, "nat not enabled\n");
218828679Sbrian    }
218935449Sbrian  }
219028679Sbrian  return -1;
219126031Sbrian}
219250059Sbrian#endif /* #ifndef NONAT */
219331121Sbrian
219431121Sbrianstatic int
219536285SbrianLinkCommand(struct cmdargs const *arg)
219636285Sbrian{
219736285Sbrian  if (arg->argc > arg->argn+1) {
219836285Sbrian    char namelist[LINE_LEN];
219936285Sbrian    struct datalink *cx;
220036285Sbrian    char *name;
220136285Sbrian    int result = 0;
220236285Sbrian
220336285Sbrian    if (!strcmp(arg->argv[arg->argn], "*")) {
220436285Sbrian      struct datalink *dl;
220536285Sbrian
220636285Sbrian      cx = arg->bundle->links;
220736285Sbrian      while (cx) {
220836285Sbrian        /* Watch it, the command could be a ``remove'' */
220936285Sbrian        dl = cx->next;
221036285Sbrian        FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
221136285Sbrian                 arg->prompt, cx);
221236285Sbrian        for (cx = arg->bundle->links; cx; cx = cx->next)
221336285Sbrian          if (cx == dl)
221436285Sbrian            break;		/* Pointer's still valid ! */
221536285Sbrian      }
221636285Sbrian    } else {
221736285Sbrian      strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
221836285Sbrian      namelist[sizeof namelist - 1] = '\0';
221936285Sbrian      for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
222036285Sbrian        if (!bundle2datalink(arg->bundle, name)) {
222136285Sbrian          log_Printf(LogWARN, "link: %s: Invalid link name\n", name);
222236285Sbrian          return 1;
222336285Sbrian        }
222436285Sbrian
222536285Sbrian      strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
222636285Sbrian      namelist[sizeof namelist - 1] = '\0';
222736285Sbrian      for(name = strtok(namelist, ", "); name; name = strtok(NULL,", ")) {
222836285Sbrian        cx = bundle2datalink(arg->bundle, name);
222936285Sbrian        if (cx)
223036285Sbrian          FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
223136285Sbrian                   arg->prompt, cx);
223236285Sbrian        else {
223336285Sbrian          log_Printf(LogWARN, "link: %s: Invalidated link name !\n", name);
223436285Sbrian          result++;
223536285Sbrian        }
223636285Sbrian      }
223736285Sbrian    }
223836285Sbrian    return result;
223936285Sbrian  }
224036285Sbrian
224136285Sbrian  log_Printf(LogWARN, "Usage: %s\n", arg->cmd->syntax);
224236285Sbrian  return 2;
224336285Sbrian}
224436285Sbrian
224536285Sbrianstruct link *
224636285Sbriancommand_ChooseLink(struct cmdargs const *arg)
224736285Sbrian{
224836285Sbrian  if (arg->cx)
224936285Sbrian    return &arg->cx->physical->link;
225037210Sbrian  else if (!arg->bundle->ncp.mp.cfg.mrru) {
225136285Sbrian    struct datalink *dl = bundle2datalink(arg->bundle, NULL);
225237210Sbrian    if (dl)
225337210Sbrian      return &dl->physical->link;
225436285Sbrian  }
225537210Sbrian  return &arg->bundle->ncp.mp.link;
225636285Sbrian}
225736285Sbrian
225836285Sbrianstatic const char *
225936285Sbrianident_cmd(const char *cmd, unsigned *keep, unsigned *add)
226036285Sbrian{
226136285Sbrian  const char *result;
226236285Sbrian
226336285Sbrian  switch (*cmd) {
226436285Sbrian    case 'A':
226536285Sbrian    case 'a':
226636285Sbrian      result = "accept";
226736285Sbrian      *keep = NEG_MYMASK;
226836285Sbrian      *add = NEG_ACCEPTED;
226936285Sbrian      break;
227036285Sbrian    case 'D':
227136285Sbrian    case 'd':
227236285Sbrian      switch (cmd[1]) {
227336285Sbrian        case 'E':
227436285Sbrian        case 'e':
227536285Sbrian          result = "deny";
227636285Sbrian          *keep = NEG_MYMASK;
227736285Sbrian          *add = 0;
227836285Sbrian          break;
227936285Sbrian        case 'I':
228036285Sbrian        case 'i':
228136285Sbrian          result = "disable";
228236285Sbrian          *keep = NEG_HISMASK;
228336285Sbrian          *add = 0;
228436285Sbrian          break;
228536285Sbrian        default:
228636285Sbrian          return NULL;
228736285Sbrian      }
228836285Sbrian      break;
228936285Sbrian    case 'E':
229036285Sbrian    case 'e':
229136285Sbrian      result = "enable";
229236285Sbrian      *keep = NEG_HISMASK;
229336285Sbrian      *add = NEG_ENABLED;
229436285Sbrian      break;
229536285Sbrian    default:
229636285Sbrian      return NULL;
229736285Sbrian  }
229836285Sbrian
229936285Sbrian  return result;
230036285Sbrian}
230136285Sbrian
230236285Sbrianstatic int
230336285SbrianOptSet(struct cmdargs const *arg)
230436285Sbrian{
230537574Sbrian  int bit = (int)(long)arg->cmd->args;
230636285Sbrian  const char *cmd;
230736285Sbrian  unsigned keep;			/* Keep these bits */
230836285Sbrian  unsigned add;				/* Add these bits */
230936285Sbrian
231036285Sbrian  if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL)
231136285Sbrian    return 1;
231236285Sbrian
231336285Sbrian  if (add)
231436285Sbrian    arg->bundle->cfg.opt |= bit;
231536285Sbrian  else
231636285Sbrian    arg->bundle->cfg.opt &= ~bit;
231736285Sbrian  return 0;
231836285Sbrian}
231936285Sbrian
232036285Sbrianstatic int
232140561SbrianIfaceAliasOptSet(struct cmdargs const *arg)
232240561Sbrian{
232340561Sbrian  unsigned save = arg->bundle->cfg.opt;
232440561Sbrian  int result = OptSet(arg);
232540561Sbrian
232640561Sbrian  if (result == 0)
232750059Sbrian    if (Enabled(arg->bundle, OPT_IFACEALIAS) && !arg->bundle->NatEnabled) {
232840561Sbrian      arg->bundle->cfg.opt = save;
232950059Sbrian      log_Printf(LogWARN, "Cannot enable iface-alias without NAT\n");
233040561Sbrian      result = 2;
233140561Sbrian    }
233240561Sbrian
233340561Sbrian  return result;
233440561Sbrian}
233540561Sbrian
233640561Sbrianstatic int
233736285SbrianNegotiateSet(struct cmdargs const *arg)
233836285Sbrian{
233937210Sbrian  long param = (long)arg->cmd->args;
234036285Sbrian  struct link *l = command_ChooseLink(arg);	/* LOCAL_CX_OPT uses this */
234136285Sbrian  struct datalink *cx = arg->cx;	/* LOCAL_CX uses this */
234236285Sbrian  const char *cmd;
234336285Sbrian  unsigned keep;			/* Keep these bits */
234436285Sbrian  unsigned add;				/* Add these bits */
234536285Sbrian
234636285Sbrian  if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL)
234736285Sbrian    return 1;
234836285Sbrian
234936285Sbrian  if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
235036285Sbrian    log_Printf(LogWARN, "%s %s: No context (use the `link' command)\n",
235136285Sbrian              cmd, arg->cmd->name);
235236285Sbrian    return 2;
235336285Sbrian  } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
235436285Sbrian    log_Printf(LogWARN, "%s %s: Redundant context (%s) ignored\n",
235536285Sbrian              cmd, arg->cmd->name, cx->name);
235636285Sbrian    cx = NULL;
235736285Sbrian  }
235836285Sbrian
235936285Sbrian  switch (param) {
236036285Sbrian    case NEG_ACFCOMP:
236136285Sbrian      cx->physical->link.lcp.cfg.acfcomp &= keep;
236236285Sbrian      cx->physical->link.lcp.cfg.acfcomp |= add;
236336285Sbrian      break;
236444106Sbrian    case NEG_CHAP05:
236544106Sbrian      cx->physical->link.lcp.cfg.chap05 &= keep;
236644106Sbrian      cx->physical->link.lcp.cfg.chap05 |= add;
236736285Sbrian      break;
236844106Sbrian#ifdef HAVE_DES
236944106Sbrian    case NEG_CHAP80:
237044106Sbrian      cx->physical->link.lcp.cfg.chap80nt &= keep;
237144106Sbrian      cx->physical->link.lcp.cfg.chap80nt |= add;
237244106Sbrian      break;
237344106Sbrian    case NEG_CHAP80LM:
237444106Sbrian      cx->physical->link.lcp.cfg.chap80lm &= keep;
237544106Sbrian      cx->physical->link.lcp.cfg.chap80lm |= add;
237644106Sbrian      break;
237744106Sbrian#endif
237836285Sbrian    case NEG_DEFLATE:
237936285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE] &= keep;
238036285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE] |= add;
238136285Sbrian      break;
238236285Sbrian    case NEG_DNS:
238336285Sbrian      arg->bundle->ncp.ipcp.cfg.ns.dns_neg &= keep;
238436285Sbrian      arg->bundle->ncp.ipcp.cfg.ns.dns_neg |= add;
238536285Sbrian      break;
238647858Sbrian    case NEG_ENDDISC:
238747858Sbrian      arg->bundle->ncp.mp.cfg.negenddisc &= keep;
238847858Sbrian      arg->bundle->ncp.mp.cfg.negenddisc |= add;
238947858Sbrian      break;
239036285Sbrian    case NEG_LQR:
239136285Sbrian      cx->physical->link.lcp.cfg.lqr &= keep;
239236285Sbrian      cx->physical->link.lcp.cfg.lqr |= add;
239336285Sbrian      break;
239436285Sbrian    case NEG_PAP:
239536285Sbrian      cx->physical->link.lcp.cfg.pap &= keep;
239636285Sbrian      cx->physical->link.lcp.cfg.pap |= add;
239736285Sbrian      break;
239836285Sbrian    case NEG_PPPDDEFLATE:
239936285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE24] &= keep;
240036285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE24] |= add;
240136285Sbrian      break;
240236285Sbrian    case NEG_PRED1:
240336285Sbrian      l->ccp.cfg.neg[CCP_NEG_PRED1] &= keep;
240436285Sbrian      l->ccp.cfg.neg[CCP_NEG_PRED1] |= add;
240536285Sbrian      break;
240636285Sbrian    case NEG_PROTOCOMP:
240736285Sbrian      cx->physical->link.lcp.cfg.protocomp &= keep;
240836285Sbrian      cx->physical->link.lcp.cfg.protocomp |= add;
240936285Sbrian      break;
241036285Sbrian    case NEG_SHORTSEQ:
241140622Sbrian      switch (bundle_Phase(arg->bundle)) {
241240622Sbrian        case PHASE_DEAD:
241340622Sbrian          break;
241440622Sbrian        case PHASE_ESTABLISH:
241540622Sbrian          /* Make sure none of our links are DATALINK_LCP or greater */
241640622Sbrian          if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) {
241740622Sbrian            log_Printf(LogWARN, "shortseq: Only changable before"
241840622Sbrian                       " LCP negotiations\n");
241940622Sbrian            return 1;
242040622Sbrian          }
242140622Sbrian          break;
242240622Sbrian        default:
242340622Sbrian          log_Printf(LogWARN, "shortseq: Only changable at phase"
242440622Sbrian                     " DEAD/ESTABLISH\n");
242540622Sbrian          return 1;
242636285Sbrian      }
242740622Sbrian      arg->bundle->ncp.mp.cfg.shortseq &= keep;
242840622Sbrian      arg->bundle->ncp.mp.cfg.shortseq |= add;
242936285Sbrian      break;
243036285Sbrian    case NEG_VJCOMP:
243136285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.neg &= keep;
243236285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.neg |= add;
243336285Sbrian      break;
243436285Sbrian  }
243536285Sbrian
243636285Sbrian  return 0;
243736285Sbrian}
243836285Sbrian
243936285Sbrianstatic struct cmdtab const NegotiateCommands[] = {
244062778Sbrian  {"filter-decapsulation", NULL, OptSet, LOCAL_AUTH,
244162778Sbrian  "filter on PPPoUDP payloads", "disable|enable",
244262778Sbrian  (const void *)OPT_FILTERDECAP},
244336285Sbrian  {"idcheck", NULL, OptSet, LOCAL_AUTH, "Check FSM reply ids",
244436285Sbrian  "disable|enable", (const void *)OPT_IDCHECK},
244540666Sbrian  {"iface-alias", NULL, IfaceAliasOptSet, LOCAL_AUTH,
244662778Sbrian  "retain interface addresses", "disable|enable",
244762778Sbrian  (const void *)OPT_IFACEALIAS},
244847689Sbrian  {"keep-session", NULL, OptSet, LOCAL_AUTH, "Retain device session leader",
244947689Sbrian  "disable|enable", (const void *)OPT_KEEPSESSION},
245036285Sbrian  {"loopback", NULL, OptSet, LOCAL_AUTH, "Loop packets for local iface",
245136285Sbrian  "disable|enable", (const void *)OPT_LOOPBACK},
245236285Sbrian  {"passwdauth", NULL, OptSet, LOCAL_AUTH, "Use passwd file",
245336285Sbrian  "disable|enable", (const void *)OPT_PASSWDAUTH},
245440665Sbrian  {"proxy", NULL, OptSet, LOCAL_AUTH, "Create a proxy ARP entry",
245536285Sbrian  "disable|enable", (const void *)OPT_PROXY},
245640665Sbrian  {"proxyall", NULL, OptSet, LOCAL_AUTH, "Proxy ARP for all remote hosts",
245740665Sbrian  "disable|enable", (const void *)OPT_PROXYALL},
245836285Sbrian  {"sroutes", NULL, OptSet, LOCAL_AUTH, "Use sticky routes",
245936285Sbrian  "disable|enable", (const void *)OPT_SROUTES},
246036285Sbrian  {"throughput", NULL, OptSet, LOCAL_AUTH, "Rolling throughput",
246136285Sbrian  "disable|enable", (const void *)OPT_THROUGHPUT},
246236285Sbrian  {"utmp", NULL, OptSet, LOCAL_AUTH, "Log connections in utmp",
246336285Sbrian  "disable|enable", (const void *)OPT_UTMP},
246436285Sbrian
246547689Sbrian#define OPT_MAX 10	/* accept/deny allowed below and not above */
246636285Sbrian
246736285Sbrian  {"acfcomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
246836285Sbrian  "Address & Control field compression", "accept|deny|disable|enable",
246936285Sbrian  (const void *)NEG_ACFCOMP},
247044106Sbrian  {"chap", "chap05", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
247136285Sbrian  "Challenge Handshake Authentication Protocol", "accept|deny|disable|enable",
247244106Sbrian  (const void *)NEG_CHAP05},
247344106Sbrian#ifdef HAVE_DES
247444106Sbrian  {"mschap", "chap80nt", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
247544106Sbrian  "Microsoft (NT) CHAP", "accept|deny|disable|enable",
247644106Sbrian  (const void *)NEG_CHAP80},
247744106Sbrian  {"LANMan", "chap80lm", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
247844106Sbrian  "Microsoft (NT) CHAP", "accept|deny|disable|enable",
247944106Sbrian  (const void *)NEG_CHAP80LM},
248044106Sbrian#endif
248136285Sbrian  {"deflate", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
248236285Sbrian  "Deflate compression", "accept|deny|disable|enable",
248336285Sbrian  (const void *)NEG_DEFLATE},
248436285Sbrian  {"deflate24", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
248536285Sbrian  "Deflate (type 24) compression", "accept|deny|disable|enable",
248636285Sbrian  (const void *)NEG_PPPDDEFLATE},
248736285Sbrian  {"dns", NULL, NegotiateSet, LOCAL_AUTH,
248836285Sbrian  "DNS specification", "accept|deny|disable|enable", (const void *)NEG_DNS},
248947858Sbrian  {"enddisc", NULL, NegotiateSet, LOCAL_AUTH, "ENDDISC negotiation",
249047858Sbrian  "accept|deny|disable|enable", (const void *)NEG_ENDDISC},
249136285Sbrian  {"lqr", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
249236285Sbrian  "Link Quality Reports", "accept|deny|disable|enable",
249336285Sbrian  (const void *)NEG_LQR},
249436285Sbrian  {"pap", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
249536285Sbrian  "Password Authentication protocol", "accept|deny|disable|enable",
249636285Sbrian  (const void *)NEG_PAP},
249736285Sbrian  {"pred1", "predictor1", NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
249836285Sbrian  "Predictor 1 compression", "accept|deny|disable|enable",
249936285Sbrian  (const void *)NEG_PRED1},
250036285Sbrian  {"protocomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
250136285Sbrian  "Protocol field compression", "accept|deny|disable|enable",
250236285Sbrian  (const void *)NEG_PROTOCOMP},
250336285Sbrian  {"shortseq", NULL, NegotiateSet, LOCAL_AUTH,
250436285Sbrian  "MP Short Sequence Numbers", "accept|deny|disable|enable",
250536285Sbrian  (const void *)NEG_SHORTSEQ},
250636285Sbrian  {"vjcomp", NULL, NegotiateSet, LOCAL_AUTH,
250736285Sbrian  "Van Jacobson header compression", "accept|deny|disable|enable",
250836285Sbrian  (const void *)NEG_VJCOMP},
250936285Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
251036285Sbrian  "Display this message", "accept|deny|disable|enable help|? [value]",
251136285Sbrian  NegotiateCommands},
251236285Sbrian  {NULL, NULL, NULL},
251336285Sbrian};
251436285Sbrian
251536285Sbrianstatic int
251636285SbrianNegotiateCommand(struct cmdargs const *arg)
251736285Sbrian{
251836285Sbrian  if (arg->argc > arg->argn) {
251936285Sbrian    char const *argv[3];
252036285Sbrian    unsigned keep, add;
252136285Sbrian    int n;
252236285Sbrian
252336285Sbrian    if ((argv[0] = ident_cmd(arg->argv[arg->argn-1], &keep, &add)) == NULL)
252436285Sbrian      return -1;
252536285Sbrian    argv[2] = NULL;
252636285Sbrian
252736285Sbrian    for (n = arg->argn; n < arg->argc; n++) {
252836285Sbrian      argv[1] = arg->argv[n];
252936285Sbrian      FindExec(arg->bundle, NegotiateCommands + (keep == NEG_HISMASK ?
253036285Sbrian               0 : OPT_MAX), 2, 1, argv, arg->prompt, arg->cx);
253136285Sbrian    }
253236285Sbrian  } else if (arg->prompt)
253336285Sbrian    prompt_Printf(arg->prompt, "Use `%s ?' to get a list.\n",
253436285Sbrian	    arg->argv[arg->argn-1]);
253536285Sbrian  else
253636285Sbrian    log_Printf(LogWARN, "%s command must have arguments\n",
253736285Sbrian              arg->argv[arg->argn] );
253836285Sbrian
253936285Sbrian  return 0;
254036285Sbrian}
254136285Sbrian
254236285Sbrianconst char *
254336285Sbriancommand_ShowNegval(unsigned val)
254436285Sbrian{
254536285Sbrian  switch (val&3) {
254636285Sbrian    case 1: return "disabled & accepted";
254736285Sbrian    case 2: return "enabled & denied";
254836285Sbrian    case 3: return "enabled & accepted";
254936285Sbrian  }
255036285Sbrian  return "disabled & denied";
255136285Sbrian}
255236934Sbrian
255336934Sbrianstatic int
255436934SbrianClearCommand(struct cmdargs const *arg)
255536934Sbrian{
255636934Sbrian  struct pppThroughput *t;
255736934Sbrian  struct datalink *cx;
255836934Sbrian  int i, clear_type;
255936934Sbrian
256036934Sbrian  if (arg->argc < arg->argn + 1)
256136934Sbrian    return -1;
256236934Sbrian
256346686Sbrian  if (strcasecmp(arg->argv[arg->argn], "physical") == 0) {
256436934Sbrian    cx = arg->cx;
256536934Sbrian    if (!cx)
256636934Sbrian      cx = bundle2datalink(arg->bundle, NULL);
256736934Sbrian    if (!cx) {
256846686Sbrian      log_Printf(LogWARN, "A link must be specified for ``clear physical''\n");
256936934Sbrian      return 1;
257036934Sbrian    }
257136934Sbrian    t = &cx->physical->link.throughput;
257236934Sbrian  } else if (strcasecmp(arg->argv[arg->argn], "ipcp") == 0)
257336934Sbrian    t = &arg->bundle->ncp.ipcp.throughput;
257436934Sbrian  else
257536934Sbrian    return -1;
257636934Sbrian
257736934Sbrian  if (arg->argc > arg->argn + 1) {
257836934Sbrian    clear_type = 0;
257936934Sbrian    for (i = arg->argn + 1; i < arg->argc; i++)
258036934Sbrian      if (strcasecmp(arg->argv[i], "overall") == 0)
258136934Sbrian        clear_type |= THROUGHPUT_OVERALL;
258236934Sbrian      else if (strcasecmp(arg->argv[i], "current") == 0)
258336934Sbrian        clear_type |= THROUGHPUT_CURRENT;
258436934Sbrian      else if (strcasecmp(arg->argv[i], "peak") == 0)
258536934Sbrian        clear_type |= THROUGHPUT_PEAK;
258636934Sbrian      else
258736934Sbrian        return -1;
258836934Sbrian  } else
258936934Sbrian    clear_type = THROUGHPUT_ALL;
259036934Sbrian
259136934Sbrian  throughput_clear(t, clear_type, arg->prompt);
259236934Sbrian  return 0;
259336934Sbrian}
259440561Sbrian
259540561Sbrianstatic int
259640561SbrianRunListCommand(struct cmdargs const *arg)
259740561Sbrian{
259840561Sbrian  const char *cmd = arg->argc ? arg->argv[arg->argc - 1] : "???";
259940561Sbrian
260040561Sbrian  if (arg->argc > arg->argn)
260140561Sbrian    FindExec(arg->bundle, arg->cmd->args, arg->argc, arg->argn, arg->argv,
260240561Sbrian             arg->prompt, arg->cx);
260340561Sbrian  else if (arg->prompt)
260440561Sbrian    prompt_Printf(arg->prompt, "Use `%s help' to get a list or `%s help"
260540561Sbrian                  " <option>' for syntax help.\n", cmd, cmd);
260640561Sbrian  else
260740561Sbrian    log_Printf(LogWARN, "%s command must have arguments\n", cmd);
260840561Sbrian
260940561Sbrian  return 0;
261040561Sbrian}
261140561Sbrian
261240561Sbrianstatic int
261340561SbrianIfaceAddCommand(struct cmdargs const *arg)
261440561Sbrian{
261540561Sbrian  int bits, n, how;
261640561Sbrian  struct in_addr ifa, mask, brd;
261740561Sbrian
261840664Sbrian  if (arg->argc == arg->argn + 1) {
261943313Sbrian    if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, NULL, NULL))
262040561Sbrian      return -1;
262140664Sbrian    mask.s_addr = brd.s_addr = INADDR_BROADCAST;
262240664Sbrian  } else {
262340664Sbrian    if (arg->argc == arg->argn + 2) {
262443313Sbrian      if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, &mask, &bits))
262540664Sbrian        return -1;
262640664Sbrian      n = 1;
262740664Sbrian    } else if (arg->argc == arg->argn + 3) {
262843313Sbrian      if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, NULL, NULL))
262940664Sbrian        return -1;
263043313Sbrian      if (!ParseAddr(NULL, arg->argv[arg->argn + 1], &mask, NULL, NULL))
263140664Sbrian        return -1;
263240664Sbrian      n = 2;
263340664Sbrian    } else
263440561Sbrian      return -1;
263540561Sbrian
263643313Sbrian    if (!ParseAddr(NULL, arg->argv[arg->argn + n], &brd, NULL, NULL))
263740664Sbrian      return -1;
263840664Sbrian  }
263940561Sbrian
264040561Sbrian  how = IFACE_ADD_LAST;
264140561Sbrian  if (arg->cmd->args)
264240561Sbrian    how |= IFACE_FORCE_ADD;
264340561Sbrian
264440561Sbrian  return !iface_inAdd(arg->bundle->iface, ifa, mask, brd, how);
264540561Sbrian}
264640561Sbrian
264740561Sbrianstatic int
264840561SbrianIfaceDeleteCommand(struct cmdargs const *arg)
264940561Sbrian{
265040561Sbrian  struct in_addr ifa;
265140561Sbrian  int ok;
265240561Sbrian
265340561Sbrian  if (arg->argc != arg->argn + 1)
265440561Sbrian    return -1;
265540561Sbrian
265643313Sbrian  if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, NULL, NULL))
265740561Sbrian    return -1;
265840561Sbrian
265940561Sbrian  if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED &&
266040561Sbrian      arg->bundle->ncp.ipcp.my_ip.s_addr == ifa.s_addr) {
266140561Sbrian    log_Printf(LogWARN, "%s: Cannot remove active interface address\n",
266240561Sbrian               inet_ntoa(ifa));
266340561Sbrian    return 1;
266440561Sbrian  }
266540561Sbrian
266640561Sbrian  ok = iface_inDelete(arg->bundle->iface, ifa);
266740561Sbrian  if (!ok) {
266840561Sbrian    if (arg->cmd->args)
266940561Sbrian      ok = 1;
267040561Sbrian    else if (arg->prompt)
267140561Sbrian      prompt_Printf(arg->prompt, "%s: No such address\n", inet_ntoa(ifa));
267240561Sbrian    else
267340561Sbrian      log_Printf(LogWARN, "%s: No such address\n", inet_ntoa(ifa));
267440561Sbrian  }
267540561Sbrian
267640561Sbrian  return !ok;
267740561Sbrian}
267840561Sbrian
267940561Sbrianstatic int
268040561SbrianIfaceClearCommand(struct cmdargs const *arg)
268140561Sbrian{
268240561Sbrian  int how;
268340561Sbrian
268440561Sbrian  if (arg->argc != arg->argn)
268540561Sbrian    return -1;
268640561Sbrian
268740941Sbrian  how = arg->bundle->ncp.ipcp.fsm.state == ST_OPENED ||
268840941Sbrian        arg->bundle->phys_type.all & PHYS_AUTO ?
268940561Sbrian        IFACE_CLEAR_ALIASES : IFACE_CLEAR_ALL;
269040561Sbrian  iface_Clear(arg->bundle->iface, how);
269140561Sbrian
269240561Sbrian  return 0;
269340561Sbrian}
269440679Sbrian
269540679Sbrianstatic int
269640679SbrianSetProcTitle(struct cmdargs const *arg)
269740679Sbrian{
269840679Sbrian  static char title[LINE_LEN];
269940679Sbrian  char *argv[MAXARGS], *ptr;
270040679Sbrian  int len, remaining, f, argc = arg->argc - arg->argn;
270140679Sbrian
270240679Sbrian  if (arg->argc == arg->argn) {
270353298Sbrian    ID0setproctitle(NULL);
270440679Sbrian    return 0;
270540679Sbrian  }
270640679Sbrian
270740679Sbrian  if (argc >= sizeof argv / sizeof argv[0]) {
270840679Sbrian    argc = sizeof argv / sizeof argv[0] - 1;
270940679Sbrian    log_Printf(LogWARN, "Truncating proc title to %d args\n", argc);
271040679Sbrian  }
271147849Sbrian  command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 1, getpid());
271240679Sbrian
271340679Sbrian  ptr = title;
271440679Sbrian  remaining = sizeof title - 1;
271540679Sbrian  for (f = 0; f < argc && remaining; f++) {
271640679Sbrian    if (f) {
271740679Sbrian      *ptr++ = ' ';
271840679Sbrian      remaining--;
271940679Sbrian    }
272040679Sbrian    len = strlen(argv[f]);
272140679Sbrian    if (len > remaining)
272240679Sbrian      len = remaining;
272340679Sbrian    memcpy(ptr, argv[f], len);
272440679Sbrian    remaining -= len;
272540679Sbrian    ptr += len;
272640679Sbrian  }
272740679Sbrian  *ptr = '\0';
272840679Sbrian
272953298Sbrian  ID0setproctitle(title);
273040679Sbrian
273140679Sbrian  return 0;
273240679Sbrian}
2733