command.c revision 95258
178189Sbrian/*-
278189Sbrian * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org>
378189Sbrian *          based on work by Toshiharu OHNO <tony-o@iij.ad.jp>
478189Sbrian *                           Internet Initiative Japan, Inc (IIJ)
578189Sbrian * All rights reserved.
66059Samurai *
778189Sbrian * Redistribution and use in source and binary forms, with or without
878189Sbrian * modification, are permitted provided that the following conditions
978189Sbrian * are met:
1078189Sbrian * 1. Redistributions of source code must retain the above copyright
1178189Sbrian *    notice, this list of conditions and the following disclaimer.
1278189Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1378189Sbrian *    notice, this list of conditions and the following disclaimer in the
1478189Sbrian *    documentation and/or other materials provided with the distribution.
156059Samurai *
1678189Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1778189Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1878189Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1978189Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2078189Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2178189Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2278189Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2378189Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2478189Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2578189Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2678189Sbrian * SUCH DAMAGE.
276059Samurai *
2850479Speter * $FreeBSD: head/usr.sbin/ppp/command.c 95258 2002-04-22 13:44:47Z des $
296059Samurai */
3078189Sbrian
3143313Sbrian#include <sys/param.h>
3230715Sbrian#include <netinet/in_systm.h>
3326031Sbrian#include <netinet/in.h>
3430715Sbrian#include <netinet/ip.h>
3526031Sbrian#include <arpa/inet.h>
3630715Sbrian#include <sys/socket.h>
3726031Sbrian#include <net/route.h>
3830715Sbrian#include <netdb.h>
3936285Sbrian#include <sys/un.h>
4030715Sbrian
4138628Sbrian#include <ctype.h>
4230715Sbrian#include <errno.h>
4326516Sbrian#include <fcntl.h>
4430715Sbrian#include <paths.h>
4530715Sbrian#include <stdio.h>
4630715Sbrian#include <stdlib.h>
4730715Sbrian#include <string.h>
4830715Sbrian#include <sys/wait.h>
4930715Sbrian#include <termios.h>
5030715Sbrian#include <unistd.h>
5130715Sbrian
5250059Sbrian#ifndef NONAT
5358037Sbrian#ifdef LOCALNAT
5458037Sbrian#include "alias.h"
5558037Sbrian#else
5646086Sbrian#include <alias.h>
5739395Sbrian#endif
5839395Sbrian#endif
5958037Sbrian
6046686Sbrian#include "layer.h"
6137009Sbrian#include "defs.h"
6231343Sbrian#include "command.h"
6330715Sbrian#include "mbuf.h"
6430715Sbrian#include "log.h"
6530715Sbrian#include "timer.h"
666059Samurai#include "fsm.h"
6731690Sbrian#include "iplist.h"
6836285Sbrian#include "throughput.h"
6936285Sbrian#include "slcompress.h"
7038557Sbrian#include "lqr.h"
7138557Sbrian#include "hdlc.h"
7263484Sbrian#include "lcp.h"
7381634Sbrian#include "ncpaddr.h"
7481634Sbrian#include "ip.h"
756059Samurai#include "ipcp.h"
7650059Sbrian#ifndef NONAT
7751075Sbrian#include "nat_cmd.h"
7831343Sbrian#endif
7925630Sbrian#include "systems.h"
8036285Sbrian#include "filter.h"
8136285Sbrian#include "descriptor.h"
8230715Sbrian#include "main.h"
8330715Sbrian#include "route.h"
8430715Sbrian#include "ccp.h"
8531080Sbrian#include "auth.h"
8636285Sbrian#include "async.h"
8736285Sbrian#include "link.h"
8836285Sbrian#include "physical.h"
8936285Sbrian#include "mp.h"
9043313Sbrian#ifndef NORADIUS
9143313Sbrian#include "radius.h"
9243313Sbrian#endif
9381634Sbrian#include "ipv6cp.h"
9481634Sbrian#include "ncp.h"
9536285Sbrian#include "bundle.h"
9636285Sbrian#include "server.h"
9736285Sbrian#include "prompt.h"
9836285Sbrian#include "chat.h"
9936285Sbrian#include "chap.h"
10038174Sbrian#include "cbcp.h"
10136285Sbrian#include "datalink.h"
10240561Sbrian#include "iface.h"
10353298Sbrian#include "id.h"
10481697Sbrian#include "probe.h"
1056059Samurai
10636285Sbrian/* ``set'' values */
10736285Sbrian#define	VAR_AUTHKEY	0
10836285Sbrian#define	VAR_DIAL	1
10936285Sbrian#define	VAR_LOGIN	2
11036285Sbrian#define	VAR_AUTHNAME	3
11136285Sbrian#define	VAR_AUTOLOAD	4
11236285Sbrian#define	VAR_WINSIZE	5
11336285Sbrian#define	VAR_DEVICE	6
11436285Sbrian#define	VAR_ACCMAP	7
11536285Sbrian#define	VAR_MRRU	8
11636285Sbrian#define	VAR_MRU		9
11736285Sbrian#define	VAR_MTU		10
11836285Sbrian#define	VAR_OPENMODE	11
11936285Sbrian#define	VAR_PHONE	12
12036285Sbrian#define	VAR_HANGUP	13
12136285Sbrian#define	VAR_IDLETIMEOUT	14
12236285Sbrian#define	VAR_LQRPERIOD	15
12336285Sbrian#define	VAR_LCPRETRY	16
12436285Sbrian#define	VAR_CHAPRETRY	17
12536285Sbrian#define	VAR_PAPRETRY	18
12636285Sbrian#define	VAR_CCPRETRY	19
12736285Sbrian#define	VAR_IPCPRETRY	20
12836285Sbrian#define	VAR_DNS		21
12936285Sbrian#define	VAR_NBNS	22
13036285Sbrian#define	VAR_MODE	23
13138174Sbrian#define	VAR_CALLBACK	24
13238174Sbrian#define	VAR_CBCP	25
13338544Sbrian#define	VAR_CHOKED	26
13440665Sbrian#define	VAR_SENDPIPE	27
13540665Sbrian#define	VAR_RECVPIPE	28
13643313Sbrian#define	VAR_RADIUS	29
13744073Sbrian#define	VAR_CD		30
13846686Sbrian#define	VAR_PARITY	31
13946686Sbrian#define VAR_CRTSCTS	32
14050867Sbrian#define VAR_URGENTPORTS	33
14152488Sbrian#define	VAR_LOGOUT	34
14261534Sbrian#define	VAR_IFQUEUE	35
14378411Sbrian#define	VAR_MPPE	36
1446059Samurai
14536285Sbrian/* ``accept|deny|disable|enable'' masks */
14636285Sbrian#define NEG_HISMASK (1)
14736285Sbrian#define NEG_MYMASK (2)
14836285Sbrian
14936285Sbrian/* ``accept|deny|disable|enable'' values */
15036285Sbrian#define NEG_ACFCOMP	40
15144106Sbrian#define NEG_CHAP05	41
15244106Sbrian#define NEG_CHAP80	42
15344106Sbrian#define NEG_CHAP80LM	43
15444106Sbrian#define NEG_DEFLATE	44
15547858Sbrian#define NEG_DNS		45
15647858Sbrian#define NEG_ENDDISC	46
15747858Sbrian#define NEG_LQR		47
15847858Sbrian#define NEG_PAP		48
15947858Sbrian#define NEG_PPPDDEFLATE	49
16047858Sbrian#define NEG_PRED1	50
16147858Sbrian#define NEG_PROTOCOMP	51
16247858Sbrian#define NEG_SHORTSEQ	52
16347858Sbrian#define NEG_VJCOMP	53
16467910Sbrian#define NEG_MPPE	54
16567910Sbrian#define NEG_CHAP81	55
16636285Sbrian
16794894Sbrianconst char Version[] = "3.0.2";
16836285Sbrian
16936285Sbrianstatic int ShowCommand(struct cmdargs const *);
17036285Sbrianstatic int TerminalCommand(struct cmdargs const *);
17136285Sbrianstatic int QuitCommand(struct cmdargs const *);
17236285Sbrianstatic int OpenCommand(struct cmdargs const *);
17336285Sbrianstatic int CloseCommand(struct cmdargs const *);
17436285Sbrianstatic int DownCommand(struct cmdargs const *);
17536285Sbrianstatic int SetCommand(struct cmdargs const *);
17636285Sbrianstatic int LinkCommand(struct cmdargs const *);
17736285Sbrianstatic int AddCommand(struct cmdargs const *);
17836285Sbrianstatic int DeleteCommand(struct cmdargs const *);
17936285Sbrianstatic int NegotiateCommand(struct cmdargs const *);
18036934Sbrianstatic int ClearCommand(struct cmdargs const *);
18140561Sbrianstatic int RunListCommand(struct cmdargs const *);
18240561Sbrianstatic int IfaceAddCommand(struct cmdargs const *);
18340561Sbrianstatic int IfaceDeleteCommand(struct cmdargs const *);
18440561Sbrianstatic int IfaceClearCommand(struct cmdargs const *);
18540679Sbrianstatic int SetProcTitle(struct cmdargs const *);
18650059Sbrian#ifndef NONAT
18758867Sbrianstatic int NatEnable(struct cmdargs const *);
18858867Sbrianstatic int NatOption(struct cmdargs const *);
18931343Sbrian#endif
1906059Samurai
19136285Sbrianstatic const char *
19236285Sbrianshowcx(struct cmdtab const *cmd)
19336285Sbrian{
19436285Sbrian  if (cmd->lauth & LOCAL_CX)
19536285Sbrian    return "(c)";
19636285Sbrian  else if (cmd->lauth & LOCAL_CX_OPT)
19736285Sbrian    return "(o)";
19836285Sbrian
19936285Sbrian  return "";
20036285Sbrian}
20136285Sbrian
2026059Samuraistatic int
20331343SbrianHelpCommand(struct cmdargs const *arg)
2046059Samurai{
20528679Sbrian  struct cmdtab const *cmd;
20636285Sbrian  int n, cmax, dmax, cols, cxlen;
20736285Sbrian  const char *cx;
2086059Samurai
20936285Sbrian  if (!arg->prompt) {
21036285Sbrian    log_Printf(LogWARN, "help: Cannot help without a prompt\n");
21126516Sbrian    return 0;
21236285Sbrian  }
21326516Sbrian
21436285Sbrian  if (arg->argc > arg->argn) {
21536285Sbrian    for (cmd = arg->cmdtab; cmd->name || cmd->alias; cmd++)
21636285Sbrian      if ((cmd->lauth & arg->prompt->auth) &&
21736285Sbrian          ((cmd->name && !strcasecmp(cmd->name, arg->argv[arg->argn])) ||
21836285Sbrian           (cmd->alias && !strcasecmp(cmd->alias, arg->argv[arg->argn])))) {
21936285Sbrian	prompt_Printf(arg->prompt, "%s %s\n", cmd->syntax, showcx(cmd));
22028679Sbrian	return 0;
2216059Samurai      }
22226516Sbrian    return -1;
2236059Samurai  }
22436285Sbrian
22531372Sbrian  cmax = dmax = 0;
22636285Sbrian  for (cmd = arg->cmdtab; cmd->func; cmd++)
22736285Sbrian    if (cmd->name && (cmd->lauth & arg->prompt->auth)) {
22836285Sbrian      if ((n = strlen(cmd->name) + strlen(showcx(cmd))) > cmax)
22931372Sbrian        cmax = n;
23031372Sbrian      if ((n = strlen(cmd->helpmes)) > dmax)
23131372Sbrian        dmax = n;
23231372Sbrian    }
23331372Sbrian
23431372Sbrian  cols = 80 / (dmax + cmax + 3);
2356059Samurai  n = 0;
23636285Sbrian  prompt_Printf(arg->prompt, "(o) = Optional context,"
23736285Sbrian                " (c) = Context required\n");
23836285Sbrian  for (cmd = arg->cmdtab; cmd->func; cmd++)
23936285Sbrian    if (cmd->name && (cmd->lauth & arg->prompt->auth)) {
24036285Sbrian      cx = showcx(cmd);
24136285Sbrian      cxlen = cmax - strlen(cmd->name);
24240482Sbrian      if (n % cols != 0)
24340482Sbrian        prompt_Printf(arg->prompt, " ");
24440482Sbrian      prompt_Printf(arg->prompt, "%s%-*.*s: %-*.*s",
24536285Sbrian              cmd->name, cxlen, cxlen, cx, dmax, dmax, cmd->helpmes);
24631372Sbrian      if (++n % cols == 0)
24736285Sbrian        prompt_Printf(arg->prompt, "\n");
2486059Samurai    }
24931372Sbrian  if (n % cols != 0)
25036285Sbrian    prompt_Printf(arg->prompt, "\n");
25126516Sbrian
25226516Sbrian  return 0;
2536059Samurai}
2546059Samurai
25536285Sbrianstatic int
25663484SbrianIdentCommand(struct cmdargs const *arg)
25763484Sbrian{
25885991Sbrian  Concatinate(arg->cx->physical->link.lcp.cfg.ident,
25985991Sbrian              sizeof arg->cx->physical->link.lcp.cfg.ident,
26085991Sbrian              arg->argc - arg->argn, arg->argv + arg->argn);
26163484Sbrian  return 0;
26263484Sbrian}
26363484Sbrian
26463484Sbrianstatic int
26563484SbrianSendIdentification(struct cmdargs const *arg)
26663484Sbrian{
26763484Sbrian  if (arg->cx->state < DATALINK_LCP) {
26863484Sbrian    log_Printf(LogWARN, "sendident: link has not reached LCP\n");
26963484Sbrian    return 2;
27063484Sbrian  }
27163484Sbrian  return lcp_SendIdentification(&arg->cx->physical->link.lcp) ? 0 : 1;
27263484Sbrian}
27363484Sbrian
27463484Sbrianstatic int
27536285SbrianCloneCommand(struct cmdargs const *arg)
2766059Samurai{
27736285Sbrian  char namelist[LINE_LEN];
27836285Sbrian  char *name;
27936285Sbrian  int f;
2806059Samurai
28136285Sbrian  if (arg->argc == arg->argn)
28236285Sbrian    return -1;
28336285Sbrian
28436285Sbrian  namelist[sizeof namelist - 1] = '\0';
28536285Sbrian  for (f = arg->argn; f < arg->argc; f++) {
28636285Sbrian    strncpy(namelist, arg->argv[f], sizeof namelist - 1);
28736285Sbrian    for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
28836285Sbrian      bundle_DatalinkClone(arg->bundle, arg->cx, name);
2896059Samurai  }
29036285Sbrian
29136285Sbrian  return 0;
2926059Samurai}
2936059Samurai
2946059Samuraistatic int
29536285SbrianRemoveCommand(struct cmdargs const *arg)
2966059Samurai{
29736285Sbrian  if (arg->argc != arg->argn)
29836285Sbrian    return -1;
29911336Samurai
30036285Sbrian  if (arg->cx->state != DATALINK_CLOSED) {
30136285Sbrian    log_Printf(LogWARN, "remove: Cannot delete links that aren't closed\n");
30236285Sbrian    return 2;
3036059Samurai  }
30426516Sbrian
30536285Sbrian  bundle_DatalinkRemove(arg->bundle, arg->cx);
30636285Sbrian  return 0;
30736285Sbrian}
30832711Sbrian
30936285Sbrianstatic int
31036285SbrianRenameCommand(struct cmdargs const *arg)
31136285Sbrian{
31236285Sbrian  if (arg->argc != arg->argn + 1)
31336285Sbrian    return -1;
31431121Sbrian
31536285Sbrian  if (bundle_RenameDatalink(arg->bundle, arg->cx, arg->argv[arg->argn]))
31636285Sbrian    return 0;
31736285Sbrian
31836285Sbrian  log_Printf(LogWARN, "%s -> %s: target name already exists\n",
31936285Sbrian             arg->cx->name, arg->argv[arg->argn]);
32036285Sbrian  return 1;
32136285Sbrian}
32236285Sbrian
32385991Sbrianstatic int
32436285SbrianLoadCommand(struct cmdargs const *arg)
32536285Sbrian{
32640797Sbrian  const char *err;
32740797Sbrian  int n, mode;
32836285Sbrian
32940797Sbrian  mode = arg->bundle->phys_type.all;
33036285Sbrian
33140797Sbrian  if (arg->argn < arg->argc) {
33240797Sbrian    for (n = arg->argn; n < arg->argc; n++)
33340797Sbrian      if ((err = system_IsValid(arg->argv[n], arg->prompt, mode)) != NULL) {
33440797Sbrian        log_Printf(LogWARN, "%s: %s\n", arg->argv[n], err);
33540797Sbrian        return 1;
33640797Sbrian      }
33740797Sbrian
33840797Sbrian    for (n = arg->argn; n < arg->argc; n++) {
33940797Sbrian      bundle_SetLabel(arg->bundle, arg->argv[arg->argc - 1]);
34040797Sbrian      system_Select(arg->bundle, arg->argv[n], CONFFILE, arg->prompt, arg->cx);
34140797Sbrian    }
34240797Sbrian    bundle_SetLabel(arg->bundle, arg->argv[arg->argc - 1]);
34340797Sbrian  } else if ((err = system_IsValid("default", arg->prompt, mode)) != NULL) {
34440797Sbrian    log_Printf(LogWARN, "default: %s\n", err);
34536285Sbrian    return 1;
34636285Sbrian  } else {
34740797Sbrian    bundle_SetLabel(arg->bundle, "default");
34840797Sbrian    system_Select(arg->bundle, "default", CONFFILE, arg->prompt, arg->cx);
34940797Sbrian    bundle_SetLabel(arg->bundle, "default");
35036285Sbrian  }
35140797Sbrian
35226516Sbrian  return 0;
3536059Samurai}
3546059Samurai
35585991Sbrianstatic int
35685991SbrianLogCommand(struct cmdargs const *arg)
35785991Sbrian{
35885991Sbrian  char buf[LINE_LEN];
35985991Sbrian
36085991Sbrian  if (arg->argn < arg->argc) {
36185991Sbrian    char *argv[MAXARGS];
36285991Sbrian    int argc = arg->argc - arg->argn;
36385991Sbrian
36485991Sbrian    if (argc >= sizeof argv / sizeof argv[0]) {
36585991Sbrian      argc = sizeof argv / sizeof argv[0] - 1;
36685991Sbrian      log_Printf(LogWARN, "Truncating log command to %d args\n", argc);
36785991Sbrian    }
36886760Sbrian    command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 1, getpid());
36985991Sbrian    Concatinate(buf, sizeof buf, argc, (const char *const *)argv);
37085991Sbrian    log_Printf(LogLOG, "%s\n", buf);
37185991Sbrian    command_Free(argc, argv);
37285991Sbrian    return 0;
37385991Sbrian  }
37485991Sbrian
37585991Sbrian  return -1;
37685991Sbrian}
37785991Sbrian
37885991Sbrianstatic int
37936285SbrianSaveCommand(struct cmdargs const *arg)
38036285Sbrian{
38185991Sbrian  log_Printf(LogWARN, "save command is not yet implemented.\n");
38236285Sbrian  return 1;
38336285Sbrian}
38436285Sbrian
38510528Samuraistatic int
38636285SbrianDialCommand(struct cmdargs const *arg)
38728536Sbrian{
38836285Sbrian  int res;
38936285Sbrian
39036465Sbrian  if ((arg->cx && !(arg->cx->physical->type & (PHYS_INTERACTIVE|PHYS_AUTO)))
39136465Sbrian      || (!arg->cx &&
39236928Sbrian          (arg->bundle->phys_type.all & ~(PHYS_INTERACTIVE|PHYS_AUTO)))) {
39336285Sbrian    log_Printf(LogWARN, "Manual dial is only available for auto and"
39436285Sbrian              " interactive links\n");
39536285Sbrian    return 1;
39634536Sbrian  }
39736285Sbrian
39836285Sbrian  if (arg->argc > arg->argn && (res = LoadCommand(arg)) != 0)
39936285Sbrian    return res;
40036285Sbrian
40137993Sbrian  bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1);
40236285Sbrian
40336285Sbrian  return 0;
40428536Sbrian}
40528536Sbrian
40638628Sbrian#define isinword(ch) (isalnum(ch) || (ch) == '_')
40738628Sbrian
40838628Sbrianstatic char *
40938628Sbrianstrstrword(char *big, const char *little)
41038628Sbrian{
41138628Sbrian  /* Get the first occurance of the word ``little'' in ``big'' */
41238628Sbrian  char *pos;
41338628Sbrian  int len;
41438628Sbrian
41538628Sbrian  pos = big;
41638628Sbrian  len = strlen(little);
41738628Sbrian
41838628Sbrian  while ((pos = strstr(pos, little)) != NULL)
41947865Sbrian    if ((pos != big && isinword(pos[-1])) || isinword(pos[len]))
42047865Sbrian      pos++;
42147865Sbrian    else if (pos != big && pos[-1] == '\\')
42247865Sbrian      memmove(pos - 1, pos, strlen(pos) + 1);
42347865Sbrian    else
42438628Sbrian      break;
42538628Sbrian
42638628Sbrian  return pos;
42738628Sbrian}
42838628Sbrian
42938628Sbrianstatic char *
43038628Sbriansubst(char *tgt, const char *oldstr, const char *newstr)
43138628Sbrian{
43238628Sbrian  /* tgt is a malloc()d area... realloc() as necessary */
43338628Sbrian  char *word, *ntgt;
43438628Sbrian  int ltgt, loldstr, lnewstr, pos;
43538628Sbrian
43638628Sbrian  if ((word = strstrword(tgt, oldstr)) == NULL)
43738628Sbrian    return tgt;
43838628Sbrian
43938628Sbrian  ltgt = strlen(tgt) + 1;
44038628Sbrian  loldstr = strlen(oldstr);
44138628Sbrian  lnewstr = strlen(newstr);
44238628Sbrian  do {
44338628Sbrian    pos = word - tgt;
44438628Sbrian    if (loldstr > lnewstr)
44538628Sbrian      bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr);
44638628Sbrian    if (loldstr != lnewstr) {
44738628Sbrian      ntgt = realloc(tgt, ltgt += lnewstr - loldstr);
44838628Sbrian      if (ntgt == NULL)
44938628Sbrian        break;			/* Oh wonderful ! */
45038628Sbrian      word = ntgt + pos;
45138628Sbrian      tgt = ntgt;
45238628Sbrian    }
45338628Sbrian    if (lnewstr > loldstr)
45438628Sbrian      bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr);
45538628Sbrian    bcopy(newstr, word, lnewstr);
45638628Sbrian  } while ((word = strstrword(word, oldstr)));
45738628Sbrian
45838628Sbrian  return tgt;
45938628Sbrian}
46038628Sbrian
46194934Sbrianstatic char *
46294934Sbriansubstip(char *tgt, const char *oldstr, struct in_addr ip)
46394934Sbrian{
46494934Sbrian  return subst(tgt, oldstr, inet_ntoa(ip));
46594934Sbrian}
46694934Sbrian
46794934Sbrianstatic char *
46894934Sbriansubstint(char *tgt, const char *oldstr, int i)
46994934Sbrian{
47094934Sbrian  char buf[12];
47194934Sbrian
47294934Sbrian  snprintf(buf, sizeof buf, "%d", i);
47394934Sbrian
47494934Sbrian  return subst(tgt, oldstr, buf);
47594934Sbrian}
47694934Sbrian
47794934Sbrianstatic char *
47894934Sbriansubstull(char *tgt, const char *oldstr, unsigned long long ull)
47994934Sbrian{
48094934Sbrian  char buf[21];
48194934Sbrian
48294934Sbrian  snprintf(buf, sizeof buf, "%llu", ull);
48394934Sbrian
48494934Sbrian  return subst(tgt, oldstr, buf);
48594934Sbrian}
48694934Sbrian
48794934Sbrian
48894934Sbrian#ifndef NOINET6
48994934Sbrianstatic char *
49094934Sbriansubstipv6(char *tgt, const char *oldstr, const struct ncpaddr *ip)
49194934Sbrian{
49294934Sbrian    return subst(tgt, oldstr, ncpaddr_ntoa(ip));
49394934Sbrian}
49494934Sbrian#endif
49594934Sbrian
49643888Sbrianvoid
49743888Sbriancommand_Expand(char **nargv, int argc, char const *const *oargv,
49847849Sbrian               struct bundle *bundle, int inc0, pid_t pid)
49938628Sbrian{
50085991Sbrian  int arg, secs;
50194934Sbrian  char uptime[20];
50294934Sbrian  unsigned long long oin, oout, pin, pout;
50338628Sbrian
50441755Sbrian  if (inc0)
50541755Sbrian    arg = 0;		/* Start at arg 0 */
50641755Sbrian  else {
50741755Sbrian    nargv[0] = strdup(oargv[0]);
50841755Sbrian    arg = 1;
50941755Sbrian  }
51094934Sbrian
51194934Sbrian  secs = bundle_Uptime(bundle);
51294934Sbrian  snprintf(uptime, sizeof uptime, "%d:%02d:%02d",
51394934Sbrian           secs / 3600, (secs / 60) % 60, secs % 60);
51494934Sbrian  oin = bundle->ncp.ipcp.throughput.OctetsIn;
51594934Sbrian  oout = bundle->ncp.ipcp.throughput.OctetsOut;
51694934Sbrian  pin = bundle->ncp.ipcp.throughput.PacketsIn;
51794934Sbrian  pout = bundle->ncp.ipcp.throughput.PacketsOut;
51894934Sbrian#ifndef NOINET6
51994934Sbrian  oin += bundle->ncp.ipv6cp.throughput.OctetsIn;
52094934Sbrian  oout += bundle->ncp.ipv6cp.throughput.OctetsOut;
52194934Sbrian  pin += bundle->ncp.ipv6cp.throughput.PacketsIn;
52294934Sbrian  pout += bundle->ncp.ipv6cp.throughput.PacketsOut;
52394934Sbrian#endif
52494934Sbrian
52541755Sbrian  for (; arg < argc; arg++) {
52638629Sbrian    nargv[arg] = strdup(oargv[arg]);
52794934Sbrian    nargv[arg] = subst(nargv[arg], "AUTHNAME", bundle->cfg.auth.name);
52894934Sbrian    nargv[arg] = subst(nargv[arg], "COMPILATIONDATE", __DATE__);
52994934Sbrian    nargv[arg] = substip(nargv[arg], "DNS0", bundle->ncp.ipcp.ns.dns[0]);
53094934Sbrian    nargv[arg] = substip(nargv[arg], "DNS1", bundle->ncp.ipcp.ns.dns[1]);
53194934Sbrian    nargv[arg] = subst(nargv[arg], "ENDDISC",
53294934Sbrian                       mp_Enddisc(bundle->ncp.mp.cfg.enddisc.class,
53394934Sbrian                                  bundle->ncp.mp.cfg.enddisc.address,
53494934Sbrian                                  bundle->ncp.mp.cfg.enddisc.len));
53594934Sbrian    nargv[arg] = substip(nargv[arg], "HISADDR", bundle->ncp.ipcp.peer_ip);
53681634Sbrian#ifndef NOINET6
53794934Sbrian    nargv[arg] = substipv6(nargv[arg], "HISADDR6", &bundle->ncp.ipv6cp.hisaddr);
53881634Sbrian#endif
53940561Sbrian    nargv[arg] = subst(nargv[arg], "INTERFACE", bundle->iface->name);
54094934Sbrian    nargv[arg] = substull(nargv[arg], "IPOCTETSIN",
54194934Sbrian                          bundle->ncp.ipcp.throughput.OctetsIn);
54294934Sbrian    nargv[arg] = substull(nargv[arg], "IPOCTETSOUT",
54394934Sbrian                          bundle->ncp.ipcp.throughput.OctetsOut);
54494934Sbrian    nargv[arg] = substull(nargv[arg], "IPPACKETSIN",
54594934Sbrian                          bundle->ncp.ipcp.throughput.PacketsIn);
54694934Sbrian    nargv[arg] = substull(nargv[arg], "IPPACKETSOUT",
54794934Sbrian                          bundle->ncp.ipcp.throughput.PacketsOut);
54881634Sbrian#ifndef NOINET6
54994934Sbrian    nargv[arg] = substull(nargv[arg], "IPV6OCTETSIN",
55094934Sbrian                          bundle->ncp.ipv6cp.throughput.OctetsIn);
55194934Sbrian    nargv[arg] = substull(nargv[arg], "IPV6OCTETSOUT",
55294934Sbrian                          bundle->ncp.ipv6cp.throughput.OctetsOut);
55394934Sbrian    nargv[arg] = substull(nargv[arg], "IPV6PACKETSIN",
55494934Sbrian                          bundle->ncp.ipv6cp.throughput.PacketsIn);
55594934Sbrian    nargv[arg] = substull(nargv[arg], "IPV6PACKETSOUT",
55694934Sbrian                          bundle->ncp.ipv6cp.throughput.PacketsOut);
55781634Sbrian#endif
55894934Sbrian    nargv[arg] = subst(nargv[arg], "LABEL", bundle_GetLabel(bundle));
55994934Sbrian    nargv[arg] = substip(nargv[arg], "MYADDR", bundle->ncp.ipcp.my_ip);
56094934Sbrian#ifndef NOINET6
56194934Sbrian    nargv[arg] = substipv6(nargv[arg], "MYADDR6", &bundle->ncp.ipv6cp.myaddr);
56294934Sbrian#endif
56394934Sbrian    nargv[arg] = substull(nargv[arg], "OCTETSIN", oin);
56494934Sbrian    nargv[arg] = substull(nargv[arg], "OCTETSOUT", oout);
56594934Sbrian    nargv[arg] = substull(nargv[arg], "PACKETSIN", pin);
56694934Sbrian    nargv[arg] = substull(nargv[arg], "PACKETSOUT", pout);
56738629Sbrian    nargv[arg] = subst(nargv[arg], "PEER_ENDDISC",
56838629Sbrian                       mp_Enddisc(bundle->ncp.mp.peer.enddisc.class,
56938629Sbrian                                  bundle->ncp.mp.peer.enddisc.address,
57038629Sbrian                                  bundle->ncp.mp.peer.enddisc.len));
57194934Sbrian    nargv[arg] = substint(nargv[arg], "PROCESSID", pid);
57294934Sbrian    if (server.cfg.port)
57394934Sbrian      nargv[arg] = substint(nargv[arg], "SOCKNAME", server.cfg.port);
57494934Sbrian    else
57594934Sbrian      nargv[arg] = subst(nargv[arg], "SOCKNAME", server.cfg.sockname);
57694934Sbrian    nargv[arg] = subst(nargv[arg], "UPTIME", uptime);
57794934Sbrian    nargv[arg] = subst(nargv[arg], "USER", bundle->ncp.mp.peer.authname);
57863484Sbrian    nargv[arg] = subst(nargv[arg], "VERSION", Version);
57938628Sbrian  }
58038628Sbrian  nargv[arg] = NULL;
58138628Sbrian}
58238628Sbrian
58385991Sbrianvoid
58485991Sbriancommand_Free(int argc, char **argv)
58585991Sbrian{
58685991Sbrian  while (argc) {
58785991Sbrian    free(*argv);
58885991Sbrian    argc--;
58985991Sbrian    argv++;
59085991Sbrian  }
59185991Sbrian}
59285991Sbrian
59328536Sbrianstatic int
59431343SbrianShellCommand(struct cmdargs const *arg, int bg)
59510528Samurai{
59610528Samurai  const char *shell;
59747849Sbrian  pid_t shpid, pid;
59820813Sjkh
59918856Ssos#ifdef SHELL_ONLY_INTERACTIVELY
60026911Sbrian  /* we're only allowed to shell when we run ppp interactively */
60136285Sbrian  if (arg->prompt && arg->prompt->owner) {
60236285Sbrian    log_Printf(LogWARN, "Can't start a shell from a network connection\n");
60326516Sbrian    return 1;
60410528Samurai  }
60526911Sbrian#endif
60628679Sbrian
60736285Sbrian  if (arg->argc == arg->argn) {
60836285Sbrian    if (!arg->prompt) {
60936285Sbrian      log_Printf(LogWARN, "Can't start an interactive shell from"
61036285Sbrian                " a config file\n");
61128381Sbrian      return 1;
61236285Sbrian    } else if (arg->prompt->owner) {
61336285Sbrian      log_Printf(LogWARN, "Can't start an interactive shell from"
61436285Sbrian                " a socket connection\n");
61536285Sbrian      return 1;
61628381Sbrian    } else if (bg) {
61736285Sbrian      log_Printf(LogWARN, "Can only start an interactive shell in"
61828679Sbrian		" the foreground mode\n");
61928381Sbrian      return 1;
62028381Sbrian    }
62134536Sbrian  }
62234536Sbrian
62347849Sbrian  pid = getpid();
62428679Sbrian  if ((shpid = fork()) == 0) {
62536285Sbrian    int i, fd;
62618531Sbde
62736285Sbrian    if ((shell = getenv("SHELL")) == 0)
62836285Sbrian      shell = _PATH_BSHELL;
62932017Sbrian
63036285Sbrian    timer_TermService();
63136285Sbrian
63236285Sbrian    if (arg->prompt)
63336285Sbrian      fd = arg->prompt->fd_out;
63436285Sbrian    else if ((fd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
63536285Sbrian      log_Printf(LogALERT, "Failed to open %s: %s\n",
63636285Sbrian                _PATH_DEVNULL, strerror(errno));
63728679Sbrian      exit(1);
63828679Sbrian    }
63949976Sbrian    dup2(fd, STDIN_FILENO);
64049976Sbrian    dup2(fd, STDOUT_FILENO);
64149976Sbrian    dup2(fd, STDERR_FILENO);
64249976Sbrian    for (i = getdtablesize(); i > STDERR_FILENO; i--)
64349976Sbrian      fcntl(i, F_SETFD, 1);
64426516Sbrian
64564802Sbrian#ifndef NOSUID
64655252Sbrian    setuid(ID0realuid());
64764802Sbrian#endif
64836285Sbrian    if (arg->argc > arg->argn) {
64928679Sbrian      /* substitute pseudo args */
65038628Sbrian      char *argv[MAXARGS];
65138628Sbrian      int argc = arg->argc - arg->argn;
65238628Sbrian
65338628Sbrian      if (argc >= sizeof argv / sizeof argv[0]) {
65438628Sbrian        argc = sizeof argv / sizeof argv[0] - 1;
65538628Sbrian        log_Printf(LogWARN, "Truncating shell command to %d args\n", argc);
65631343Sbrian      }
65747849Sbrian      command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 0, pid);
65828679Sbrian      if (bg) {
65928679Sbrian	pid_t p;
66010528Samurai
66128679Sbrian	p = getpid();
66228679Sbrian	if (daemon(1, 1) == -1) {
66336832Sbrian	  log_Printf(LogERROR, "%d: daemon: %s\n", (int)p, strerror(errno));
66428679Sbrian	  exit(1);
66528679Sbrian	}
66636285Sbrian      } else if (arg->prompt)
66736285Sbrian        printf("ppp: Pausing until %s finishes\n", arg->argv[arg->argn]);
66831343Sbrian      execvp(argv[0], argv);
66930316Sbrian    } else {
67036285Sbrian      if (arg->prompt)
67132017Sbrian        printf("ppp: Pausing until %s finishes\n", shell);
67236285Sbrian      prompt_TtyOldMode(arg->prompt);
67379450Sbrian      execl(shell, shell, (char *)NULL);
67430316Sbrian    }
67520813Sjkh
67640665Sbrian    log_Printf(LogWARN, "exec() of %s failed: %s\n",
67740665Sbrian              arg->argc > arg->argn ? arg->argv[arg->argn] : shell,
67840665Sbrian              strerror(errno));
67949976Sbrian    _exit(255);
68010528Samurai  }
68136285Sbrian
68236285Sbrian  if (shpid == (pid_t) - 1)
68336285Sbrian    log_Printf(LogERROR, "Fork failed: %s\n", strerror(errno));
68436285Sbrian  else {
68510528Samurai    int status;
68631343Sbrian    waitpid(shpid, &status, 0);
68710528Samurai  }
68820813Sjkh
68936285Sbrian  if (arg->prompt && !arg->prompt->owner)
69036285Sbrian    prompt_TtyCommandMode(arg->prompt);
69120813Sjkh
69236285Sbrian  return 0;
69310528Samurai}
69410528Samurai
69531343Sbrianstatic int
69631343SbrianBgShellCommand(struct cmdargs const *arg)
69731343Sbrian{
69836285Sbrian  if (arg->argc == arg->argn)
69931343Sbrian    return -1;
70031343Sbrian  return ShellCommand(arg, 1);
70131343Sbrian}
70231343Sbrian
70331343Sbrianstatic int
70431343SbrianFgShellCommand(struct cmdargs const *arg)
70531343Sbrian{
70631343Sbrian  return ShellCommand(arg, 0);
70731343Sbrian}
70831343Sbrian
70958044Sbrianstatic int
71058044SbrianResolvCommand(struct cmdargs const *arg)
71158044Sbrian{
71258044Sbrian  if (arg->argc == arg->argn + 1) {
71358044Sbrian    if (!strcasecmp(arg->argv[arg->argn], "reload"))
71458044Sbrian      ipcp_LoadDNS(&arg->bundle->ncp.ipcp);
71558044Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "restore"))
71658044Sbrian      ipcp_RestoreDNS(&arg->bundle->ncp.ipcp);
71758044Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "rewrite"))
71858044Sbrian      ipcp_WriteDNS(&arg->bundle->ncp.ipcp);
71958044Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "readonly"))
72058044Sbrian      arg->bundle->ncp.ipcp.ns.writable = 0;
72158044Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "writable"))
72258044Sbrian      arg->bundle->ncp.ipcp.ns.writable = 1;
72358044Sbrian    else
72458044Sbrian      return -1;
72558044Sbrian
72658044Sbrian    return 0;
72758044Sbrian  }
72858044Sbrian
72958044Sbrian  return -1;
73058044Sbrian}
73158044Sbrian
73250059Sbrian#ifndef NONAT
73358867Sbrianstatic struct cmdtab const NatCommands[] =
73440561Sbrian{
73550059Sbrian  {"addr", NULL, nat_RedirectAddr, LOCAL_AUTH,
73650059Sbrian   "static address translation", "nat addr [addr_local addr_alias]"},
73758867Sbrian  {"deny_incoming", NULL, NatOption, LOCAL_AUTH,
73850059Sbrian   "stop incoming connections", "nat deny_incoming yes|no",
73940561Sbrian   (const void *) PKT_ALIAS_DENY_INCOMING},
74058867Sbrian  {"enable", NULL, NatEnable, LOCAL_AUTH,
74150059Sbrian   "enable NAT", "nat enable yes|no"},
74258867Sbrian  {"log", NULL, NatOption, LOCAL_AUTH,
74350059Sbrian   "log NAT link creation", "nat log yes|no",
74440561Sbrian   (const void *) PKT_ALIAS_LOG},
74550059Sbrian  {"port", NULL, nat_RedirectPort, LOCAL_AUTH, "port redirection",
74650059Sbrian   "nat port proto localaddr:port[-port] aliasport[-aliasport]"},
74779433Sbrian  {"proto", NULL, nat_RedirectProto, LOCAL_AUTH, "protocol redirection",
74879433Sbrian   "nat proto proto localIP [publicIP [remoteIP]]"},
74950059Sbrian  {"proxy", NULL, nat_ProxyRule, LOCAL_AUTH,
75050059Sbrian   "proxy control", "nat proxy server host[:port] ..."},
75181033Sbrian#ifndef NO_FW_PUNCH
75281033Sbrian  {"punch_fw", NULL, nat_PunchFW, LOCAL_AUTH,
75381033Sbrian   "firewall control", "nat punch_fw [base count]"},
75481033Sbrian#endif
75558867Sbrian  {"same_ports", NULL, NatOption, LOCAL_AUTH,
75650059Sbrian   "try to leave port numbers unchanged", "nat same_ports yes|no",
75740561Sbrian   (const void *) PKT_ALIAS_SAME_PORTS},
75858867Sbrian  {"target", NULL, nat_SetTarget, LOCAL_AUTH,
75958867Sbrian   "Default address for incoming connections", "nat target addr" },
76058867Sbrian  {"unregistered_only", NULL, NatOption, LOCAL_AUTH,
76150059Sbrian   "translate unregistered (private) IP address space only",
76250059Sbrian   "nat unregistered_only yes|no",
76340561Sbrian   (const void *) PKT_ALIAS_UNREGISTERED_ONLY},
76458867Sbrian  {"use_sockets", NULL, NatOption, LOCAL_AUTH,
76550059Sbrian   "allocate host sockets", "nat use_sockets yes|no",
76640561Sbrian   (const void *) PKT_ALIAS_USE_SOCKETS},
76740561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
76858867Sbrian   "Display this message", "nat help|? [command]", NatCommands},
76940561Sbrian  {NULL, NULL, NULL},
77040561Sbrian};
77140561Sbrian#endif
77240561Sbrian
77340561Sbrianstatic struct cmdtab const AllowCommands[] = {
77440561Sbrian  {"modes", "mode", AllowModes, LOCAL_AUTH,
77540561Sbrian  "Only allow certain ppp modes", "allow modes mode..."},
77640561Sbrian  {"users", "user", AllowUsers, LOCAL_AUTH,
77740561Sbrian  "Only allow ppp access to certain users", "allow users logname..."},
77840561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
77940561Sbrian  "Display this message", "allow help|? [command]", AllowCommands},
78040561Sbrian  {NULL, NULL, NULL},
78140561Sbrian};
78240561Sbrian
78340561Sbrianstatic struct cmdtab const IfaceCommands[] =
78440561Sbrian{
78540561Sbrian  {"add", NULL, IfaceAddCommand, LOCAL_AUTH,
78640561Sbrian   "Add iface address", "iface add addr[/bits| mask] peer", NULL},
78740561Sbrian  {NULL, "add!", IfaceAddCommand, LOCAL_AUTH,
78840561Sbrian   "Add or change an iface address", "iface add! addr[/bits| mask] peer",
78940561Sbrian   (void *)1},
79040561Sbrian  {"clear", NULL, IfaceClearCommand, LOCAL_AUTH,
79181634Sbrian   "Clear iface address(es)", "iface clear [INET | INET6]"},
79240561Sbrian  {"delete", "rm", IfaceDeleteCommand, LOCAL_AUTH,
79340561Sbrian   "Delete iface address", "iface delete addr", NULL},
79440561Sbrian  {NULL, "rm!", IfaceDeleteCommand, LOCAL_AUTH,
79540561Sbrian   "Delete iface address", "iface delete addr", (void *)1},
79640561Sbrian  {NULL, "delete!", IfaceDeleteCommand, LOCAL_AUTH,
79740561Sbrian   "Delete iface address", "iface delete addr", (void *)1},
79840561Sbrian  {"show", NULL, iface_Show, LOCAL_AUTH,
79940561Sbrian   "Show iface address(es)", "iface show"},
80040561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
80150059Sbrian   "Display this message", "nat help|? [command]", IfaceCommands},
80240561Sbrian  {NULL, NULL, NULL},
80340561Sbrian};
80440561Sbrian
80530715Sbrianstatic struct cmdtab const Commands[] = {
80636285Sbrian  {"accept", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
80728679Sbrian  "accept option request", "accept option .."},
80828679Sbrian  {"add", NULL, AddCommand, LOCAL_AUTH,
80932109Sbrian  "add route", "add dest mask gateway", NULL},
81036285Sbrian  {NULL, "add!", AddCommand, LOCAL_AUTH,
81132109Sbrian  "add or change route", "add! dest mask gateway", (void *)1},
81240561Sbrian  {"allow", "auth", RunListCommand, LOCAL_AUTH,
81340561Sbrian  "Allow ppp access", "allow users|modes ....", AllowCommands},
81428679Sbrian  {"bg", "!bg", BgShellCommand, LOCAL_AUTH,
81531372Sbrian  "Run a background command", "[!]bg command"},
81636934Sbrian  {"clear", NULL, ClearCommand, LOCAL_AUTH | LOCAL_CX_OPT,
81746686Sbrian  "Clear throughput statistics",
81881634Sbrian  "clear ipcp|ipv6cp|physical [current|overall|peak]..."},
81936285Sbrian  {"clone", NULL, CloneCommand, LOCAL_AUTH | LOCAL_CX,
82036285Sbrian  "Clone a link", "clone newname..."},
82136285Sbrian  {"close", NULL, CloseCommand, LOCAL_AUTH | LOCAL_CX_OPT,
82236285Sbrian  "Close an FSM", "close [lcp|ccp]"},
82328679Sbrian  {"delete", NULL, DeleteCommand, LOCAL_AUTH,
82432109Sbrian  "delete route", "delete dest", NULL},
82536285Sbrian  {NULL, "delete!", DeleteCommand, LOCAL_AUTH,
82632109Sbrian  "delete a route if it exists", "delete! dest", (void *)1},
82736285Sbrian  {"deny", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
82828679Sbrian  "Deny option request", "deny option .."},
82936285Sbrian  {"dial", "call", DialCommand, LOCAL_AUTH | LOCAL_CX_OPT,
83040797Sbrian  "Dial and login", "dial|call [system ...]", NULL},
83136285Sbrian  {"disable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
83228679Sbrian  "Disable option", "disable option .."},
83336285Sbrian  {"down", NULL, DownCommand, LOCAL_AUTH | LOCAL_CX_OPT,
83446686Sbrian  "Generate a down event", "down [ccp|lcp]"},
83536285Sbrian  {"enable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
83628679Sbrian  "Enable option", "enable option .."},
83763484Sbrian  {"ident", NULL, IdentCommand, LOCAL_AUTH | LOCAL_CX,
83863484Sbrian  "Set the link identity", "ident text..."},
83940561Sbrian  {"iface", "interface", RunListCommand, LOCAL_AUTH,
84040561Sbrian  "interface control", "iface option ...", IfaceCommands},
84136285Sbrian  {"link", "datalink", LinkCommand, LOCAL_AUTH,
84236285Sbrian  "Link specific commands", "link name command ..."},
84337008Sbrian  {"load", NULL, LoadCommand, LOCAL_AUTH | LOCAL_CX_OPT,
84440797Sbrian  "Load settings", "load [system ...]"},
84585991Sbrian  {"log", NULL, LogCommand, LOCAL_AUTH | LOCAL_CX_OPT,
84685991Sbrian  "log information", "log word ..."},
84750059Sbrian#ifndef NONAT
84850059Sbrian  {"nat", "alias", RunListCommand, LOCAL_AUTH,
84958867Sbrian  "NAT control", "nat option yes|no", NatCommands},
85050059Sbrian#endif
85136285Sbrian  {"open", NULL, OpenCommand, LOCAL_AUTH | LOCAL_CX_OPT,
85237955Sbrian  "Open an FSM", "open! [lcp|ccp|ipcp]", (void *)1},
85336285Sbrian  {"passwd", NULL, PasswdCommand, LOCAL_NO_AUTH,
85436285Sbrian  "Password for manipulation", "passwd LocalPassword"},
85536285Sbrian  {"quit", "bye", QuitCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
85636285Sbrian  "Quit PPP program", "quit|bye [all]"},
85736285Sbrian  {"remove", "rm", RemoveCommand, LOCAL_AUTH | LOCAL_CX,
85836285Sbrian  "Remove a link", "remove"},
85936285Sbrian  {"rename", "mv", RenameCommand, LOCAL_AUTH | LOCAL_CX,
86036285Sbrian  "Rename a link", "rename name"},
86158044Sbrian  {"resolv", NULL, ResolvCommand, LOCAL_AUTH,
86258044Sbrian  "Manipulate resolv.conf", "resolv readonly|reload|restore|rewrite|writable"},
86328679Sbrian  {"save", NULL, SaveCommand, LOCAL_AUTH,
86428679Sbrian  "Save settings", "save"},
86563484Sbrian  {"sendident", NULL, SendIdentification, LOCAL_AUTH | LOCAL_CX,
86663484Sbrian  "Transmit the link identity", "sendident"},
86736285Sbrian  {"set", "setup", SetCommand, LOCAL_AUTH | LOCAL_CX_OPT,
86828679Sbrian  "Set parameters", "set[up] var value"},
86928679Sbrian  {"shell", "!", FgShellCommand, LOCAL_AUTH,
87028679Sbrian  "Run a subshell", "shell|! [sh command]"},
87136285Sbrian  {"show", NULL, ShowCommand, LOCAL_AUTH | LOCAL_CX_OPT,
87231372Sbrian  "Show status and stats", "show var"},
87336285Sbrian  {"term", NULL, TerminalCommand, LOCAL_AUTH | LOCAL_CX,
87431372Sbrian  "Enter terminal mode", "term"},
87528679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
87631343Sbrian  "Display this message", "help|? [command]", Commands},
87728679Sbrian  {NULL, NULL, NULL},
8786059Samurai};
8796059Samurai
88028536Sbrianstatic int
88131343SbrianShowEscape(struct cmdargs const *arg)
8826059Samurai{
88336285Sbrian  if (arg->cx->physical->async.cfg.EscMap[32]) {
88436285Sbrian    int code, bit;
88536285Sbrian    const char *sep = "";
8866059Samurai
88726516Sbrian    for (code = 0; code < 32; code++)
88836285Sbrian      if (arg->cx->physical->async.cfg.EscMap[code])
88928679Sbrian	for (bit = 0; bit < 8; bit++)
89036285Sbrian	  if (arg->cx->physical->async.cfg.EscMap[code] & (1 << bit)) {
89136285Sbrian	    prompt_Printf(arg->prompt, "%s0x%02x", sep, (code << 3) + bit);
89236285Sbrian            sep = ", ";
89336285Sbrian          }
89436285Sbrian    prompt_Printf(arg->prompt, "\n");
8956059Samurai  }
89631077Sbrian  return 0;
8976059Samurai}
8986059Samurai
89928679Sbrianstatic int
90036285SbrianShowTimerList(struct cmdargs const *arg)
9016059Samurai{
90236285Sbrian  timer_Show(0, arg->prompt);
90331077Sbrian  return 0;
9046059Samurai}
9056059Samurai
90628679Sbrianstatic int
90731343SbrianShowStopped(struct cmdargs const *arg)
90828327Sbrian{
90936285Sbrian  prompt_Printf(arg->prompt, " Stopped Timer:  LCP: ");
91036285Sbrian  if (!arg->cx->physical->link.lcp.fsm.StoppedTimer.load)
91136285Sbrian    prompt_Printf(arg->prompt, "Disabled");
91228327Sbrian  else
91336285Sbrian    prompt_Printf(arg->prompt, "%ld secs",
91436285Sbrian                  arg->cx->physical->link.lcp.fsm.StoppedTimer.load / SECTICKS);
91528461Sbrian
91636285Sbrian  prompt_Printf(arg->prompt, ", CCP: ");
91736285Sbrian  if (!arg->cx->physical->link.ccp.fsm.StoppedTimer.load)
91836285Sbrian    prompt_Printf(arg->prompt, "Disabled");
91928461Sbrian  else
92036285Sbrian    prompt_Printf(arg->prompt, "%ld secs",
92136285Sbrian                  arg->cx->physical->link.ccp.fsm.StoppedTimer.load / SECTICKS);
92228461Sbrian
92336285Sbrian  prompt_Printf(arg->prompt, "\n");
92428461Sbrian
92531077Sbrian  return 0;
92628327Sbrian}
92728327Sbrian
92828679Sbrianstatic int
92931343SbrianShowVersion(struct cmdargs const *arg)
9306059Samurai{
93151026Sbrian  prompt_Printf(arg->prompt, "PPP Version %s - %s\n", Version, __DATE__);
93231077Sbrian  return 0;
9336059Samurai}
9346059Samurai
93528679Sbrianstatic int
93636285SbrianShowProtocolStats(struct cmdargs const *arg)
93726326Sbrian{
93836285Sbrian  struct link *l = command_ChooseLink(arg);
93926326Sbrian
94036285Sbrian  prompt_Printf(arg->prompt, "%s:\n", l->name);
94136285Sbrian  link_ReportProtocolStatus(l, arg->prompt);
94231077Sbrian  return 0;
94326326Sbrian}
94426326Sbrian
94530715Sbrianstatic struct cmdtab const ShowCommands[] = {
94636285Sbrian  {"bundle", NULL, bundle_ShowStatus, LOCAL_AUTH,
94736285Sbrian  "bundle details", "show bundle"},
94836285Sbrian  {"ccp", NULL, ccp_ReportStatus, LOCAL_AUTH | LOCAL_CX_OPT,
94936285Sbrian  "CCP status", "show cpp"},
95036285Sbrian  {"compress", NULL, sl_Show, LOCAL_AUTH,
95136285Sbrian  "VJ compression stats", "show compress"},
95236285Sbrian  {"escape", NULL, ShowEscape, LOCAL_AUTH | LOCAL_CX,
95336285Sbrian  "escape characters", "show escape"},
95436285Sbrian  {"filter", NULL, filter_Show, LOCAL_AUTH,
95536285Sbrian  "packet filters", "show filter [in|out|dial|alive]"},
95636285Sbrian  {"hdlc", NULL, hdlc_ReportStatus, LOCAL_AUTH | LOCAL_CX,
95736285Sbrian  "HDLC errors", "show hdlc"},
95840561Sbrian  {"iface", "interface", iface_Show, LOCAL_AUTH,
95940561Sbrian  "Interface status", "show iface"},
96036285Sbrian  {"ipcp", NULL, ipcp_Show, LOCAL_AUTH,
96136285Sbrian  "IPCP status", "show ipcp"},
96281634Sbrian#ifndef NOINET6
96381634Sbrian  {"ipv6cp", NULL, ipv6cp_Show, LOCAL_AUTH,
96481634Sbrian  "IPV6CP status", "show ipv6cp"},
96581634Sbrian#endif
96647211Sbrian  {"layers", NULL, link_ShowLayers, LOCAL_AUTH | LOCAL_CX_OPT,
96747211Sbrian  "Protocol layers", "show layers"},
96836285Sbrian  {"lcp", NULL, lcp_ReportStatus, LOCAL_AUTH | LOCAL_CX,
96936285Sbrian  "LCP status", "show lcp"},
97036285Sbrian  {"link", "datalink", datalink_Show, LOCAL_AUTH | LOCAL_CX,
97136285Sbrian  "(high-level) link info", "show link"},
97236285Sbrian  {"links", NULL, bundle_ShowLinks, LOCAL_AUTH,
97336285Sbrian  "available link names", "show links"},
97436285Sbrian  {"log", NULL, log_ShowLevel, LOCAL_AUTH,
97536285Sbrian  "log levels", "show log"},
97636285Sbrian  {"mem", NULL, mbuf_Show, LOCAL_AUTH,
97736285Sbrian  "mbuf allocations", "show mem"},
97881634Sbrian  {"ncp", NULL, ncp_Show, LOCAL_AUTH,
97981634Sbrian  "NCP status", "show ncp"},
98046686Sbrian  {"physical", NULL, physical_ShowStatus, LOCAL_AUTH | LOCAL_CX,
98146686Sbrian  "(low-level) link info", "show physical"},
98236285Sbrian  {"mp", "multilink", mp_ShowStatus, LOCAL_AUTH,
98336285Sbrian  "multilink setup", "show mp"},
98436285Sbrian  {"proto", NULL, ShowProtocolStats, LOCAL_AUTH | LOCAL_CX_OPT,
98536285Sbrian  "protocol summary", "show proto"},
98636285Sbrian  {"route", NULL, route_Show, LOCAL_AUTH,
98736285Sbrian  "routing table", "show route"},
98836285Sbrian  {"stopped", NULL, ShowStopped, LOCAL_AUTH | LOCAL_CX,
98936285Sbrian  "STOPPED timeout", "show stopped"},
99036285Sbrian  {"timers", NULL, ShowTimerList, LOCAL_AUTH,
99136285Sbrian  "alarm timers", "show timers"},
99228679Sbrian  {"version", NULL, ShowVersion, LOCAL_NO_AUTH | LOCAL_AUTH,
99336285Sbrian  "version string", "show version"},
99436285Sbrian  {"who", NULL, log_ShowWho, LOCAL_AUTH,
99536285Sbrian  "client list", "show who"},
99628679Sbrian  {"help", "?", HelpCommand, LOCAL_NO_AUTH | LOCAL_AUTH,
99731343Sbrian  "Display this message", "show help|? [command]", ShowCommands},
99828679Sbrian  {NULL, NULL, NULL},
9996059Samurai};
10006059Samurai
100130715Sbrianstatic struct cmdtab const *
100231343SbrianFindCommand(struct cmdtab const *cmds, const char *str, int *pmatch)
10036059Samurai{
100426516Sbrian  int nmatch;
100526516Sbrian  int len;
100628679Sbrian  struct cmdtab const *found;
10076059Samurai
100826516Sbrian  found = NULL;
100926516Sbrian  len = strlen(str);
101026516Sbrian  nmatch = 0;
10116059Samurai  while (cmds->func) {
101225566Sbrian    if (cmds->name && strncasecmp(str, cmds->name, len) == 0) {
101326516Sbrian      if (cmds->name[len] == '\0') {
101428679Sbrian	*pmatch = 1;
101528679Sbrian	return cmds;
101626516Sbrian      }
10176059Samurai      nmatch++;
10186059Samurai      found = cmds;
101928679Sbrian    } else if (cmds->alias && strncasecmp(str, cmds->alias, len) == 0) {
102026516Sbrian      if (cmds->alias[len] == '\0') {
102128679Sbrian	*pmatch = 1;
102228679Sbrian	return cmds;
102326516Sbrian      }
10246059Samurai      nmatch++;
10256059Samurai      found = cmds;
10266059Samurai    }
10276059Samurai    cmds++;
10286059Samurai  }
10296059Samurai  *pmatch = nmatch;
103026516Sbrian  return found;
10316059Samurai}
10326059Samurai
103336285Sbrianstatic const char *
103436285SbrianmkPrefix(int argc, char const *const *argv, char *tgt, int sz)
103536285Sbrian{
103636285Sbrian  int f, tlen, len;
103736285Sbrian
103836285Sbrian  tlen = 0;
103936285Sbrian  for (f = 0; f < argc && tlen < sz - 2; f++) {
104036285Sbrian    if (f)
104136285Sbrian      tgt[tlen++] = ' ';
104236285Sbrian    len = strlen(argv[f]);
104336285Sbrian    if (len > sz - tlen - 1)
104436285Sbrian      len = sz - tlen - 1;
104536285Sbrian    strncpy(tgt+tlen, argv[f], len);
104636285Sbrian    tlen += len;
104736285Sbrian  }
104836285Sbrian  tgt[tlen] = '\0';
104936285Sbrian  return tgt;
105036285Sbrian}
105136285Sbrian
105230715Sbrianstatic int
105336285SbrianFindExec(struct bundle *bundle, struct cmdtab const *cmds, int argc, int argn,
105436285Sbrian         char const *const *argv, struct prompt *prompt, struct datalink *cx)
10556059Samurai{
105628679Sbrian  struct cmdtab const *cmd;
10576059Samurai  int val = 1;
10586059Samurai  int nmatch;
105931343Sbrian  struct cmdargs arg;
106036285Sbrian  char prefix[100];
10616059Samurai
106236285Sbrian  cmd = FindCommand(cmds, argv[argn], &nmatch);
10636059Samurai  if (nmatch > 1)
106436285Sbrian    log_Printf(LogWARN, "%s: Ambiguous command\n",
106536285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix));
106636285Sbrian  else if (cmd && (!prompt || (cmd->lauth & prompt->auth))) {
106736285Sbrian    if ((cmd->lauth & LOCAL_CX) && !cx)
106836285Sbrian      /* We've got no context, but we require it */
106936285Sbrian      cx = bundle2datalink(bundle, NULL);
107036285Sbrian
107136285Sbrian    if ((cmd->lauth & LOCAL_CX) && !cx)
107236285Sbrian      log_Printf(LogWARN, "%s: No context (use the `link' command)\n",
107336285Sbrian                mkPrefix(argn+1, argv, prefix, sizeof prefix));
107436285Sbrian    else {
107536285Sbrian      if (cx && !(cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
107636285Sbrian        log_Printf(LogWARN, "%s: Redundant context (%s) ignored\n",
107736285Sbrian                  mkPrefix(argn+1, argv, prefix, sizeof prefix), cx->name);
107836285Sbrian        cx = NULL;
107936285Sbrian      }
108036285Sbrian      arg.cmdtab = cmds;
108136285Sbrian      arg.cmd = cmd;
108236285Sbrian      arg.argc = argc;
108336285Sbrian      arg.argn = argn+1;
108436285Sbrian      arg.argv = argv;
108536285Sbrian      arg.bundle = bundle;
108636285Sbrian      arg.cx = cx;
108736285Sbrian      arg.prompt = prompt;
108836285Sbrian      val = (*cmd->func) (&arg);
108936285Sbrian    }
109031343Sbrian  } else
109136285Sbrian    log_Printf(LogWARN, "%s: Invalid command\n",
109236285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix));
109326516Sbrian
109426516Sbrian  if (val == -1)
109595258Sdes    log_Printf(LogWARN, "usage: %s\n", cmd->syntax);
109628679Sbrian  else if (val)
109736285Sbrian    log_Printf(LogWARN, "%s: Failed %d\n",
109836285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix), val);
109926516Sbrian
110026516Sbrian  return val;
11016059Samurai}
11026059Samurai
110337009Sbrianint
110458045Sbriancommand_Expand_Interpret(char *buff, int nb, char *argv[MAXARGS], int offset)
110558045Sbrian{
110658045Sbrian  char buff2[LINE_LEN-offset];
110758045Sbrian
110858045Sbrian  InterpretArg(buff, buff2);
110958045Sbrian  strncpy(buff, buff2, LINE_LEN - offset - 1);
111058045Sbrian  buff[LINE_LEN - offset - 1] = '\0';
111158045Sbrian
111258045Sbrian  return command_Interpret(buff, nb, argv);
111358045Sbrian}
111458045Sbrian
111558045Sbrianint
111637009Sbriancommand_Interpret(char *buff, int nb, char *argv[MAXARGS])
11176059Samurai{
11186059Samurai  char *cp;
11196059Samurai
11206059Samurai  if (nb > 0) {
11216059Samurai    cp = buff + strcspn(buff, "\r\n");
11226059Samurai    if (cp)
11236059Samurai      *cp = '\0';
112455145Sbrian    return MakeArgs(buff, argv, MAXARGS, PARSE_REDUCE);
112537009Sbrian  }
112637009Sbrian  return 0;
112731121Sbrian}
11286059Samurai
112931822Sbrianstatic int
113031822Sbrianarghidden(int argc, char const *const *argv, int n)
113131822Sbrian{
113231822Sbrian  /* Is arg n of the given command to be hidden from the log ? */
113331828Sbrian
113431828Sbrian  /* set authkey xxxxx */
113531828Sbrian  /* set key xxxxx */
113631822Sbrian  if (n == 2 && !strncasecmp(argv[0], "se", 2) &&
113731822Sbrian      (!strncasecmp(argv[1], "authk", 5) || !strncasecmp(argv[1], "ke", 2)))
113831822Sbrian    return 1;
113931822Sbrian
114031828Sbrian  /* passwd xxxxx */
114131828Sbrian  if (n == 1 && !strncasecmp(argv[0], "p", 1))
114231828Sbrian    return 1;
114331828Sbrian
114436285Sbrian  /* set server port xxxxx .... */
114536285Sbrian  if (n == 3 && !strncasecmp(argv[0], "se", 2) &&
114636285Sbrian      !strncasecmp(argv[1], "se", 2))
114736285Sbrian    return 1;
114836285Sbrian
114931822Sbrian  return 0;
115031822Sbrian}
115131822Sbrian
115231121Sbrianvoid
115336285Sbriancommand_Run(struct bundle *bundle, int argc, char const *const *argv,
115437008Sbrian           struct prompt *prompt, const char *label, struct datalink *cx)
115531121Sbrian{
115631156Sbrian  if (argc > 0) {
115736285Sbrian    if (log_IsKept(LogCOMMAND)) {
115847844Sbrian      char buf[LINE_LEN];
115931156Sbrian      int f, n;
116031156Sbrian
116131156Sbrian      if (label) {
116231962Sbrian        strncpy(buf, label, sizeof buf - 3);
116331962Sbrian        buf[sizeof buf - 3] = '\0';
116431156Sbrian        strcat(buf, ": ");
116547844Sbrian        n = strlen(buf);
116647844Sbrian      } else {
116747844Sbrian        *buf = '\0';
116847844Sbrian        n = 0;
116931156Sbrian      }
117047844Sbrian      buf[sizeof buf - 1] = '\0';	/* In case we run out of room in buf */
117147844Sbrian
117231156Sbrian      for (f = 0; f < argc; f++) {
117331962Sbrian        if (n < sizeof buf - 1 && f)
117431156Sbrian          buf[n++] = ' ';
117531822Sbrian        if (arghidden(argc, argv, f))
117636285Sbrian          strncpy(buf+n, "********", sizeof buf - n - 1);
117731822Sbrian        else
117831962Sbrian          strncpy(buf+n, argv[f], sizeof buf - n - 1);
117931156Sbrian        n += strlen(buf+n);
118031156Sbrian      }
118136285Sbrian      log_Printf(LogCOMMAND, "%s\n", buf);
118231156Sbrian    }
118337008Sbrian    FindExec(bundle, Commands, argc, 0, argv, prompt, cx);
118431156Sbrian  }
11856059Samurai}
11866059Samurai
118754914Sbrianint
118836285Sbriancommand_Decode(struct bundle *bundle, char *buff, int nb, struct prompt *prompt,
118936285Sbrian              const char *label)
119031121Sbrian{
119131121Sbrian  int argc;
119237009Sbrian  char *argv[MAXARGS];
119331121Sbrian
119458045Sbrian  if ((argc = command_Expand_Interpret(buff, nb, argv, 0)) < 0)
119554914Sbrian    return 0;
119654914Sbrian
119737008Sbrian  command_Run(bundle, argc, (char const *const *)argv, prompt, label, NULL);
119854914Sbrian  return 1;
119931121Sbrian}
120031121Sbrian
12016059Samuraistatic int
120231343SbrianShowCommand(struct cmdargs const *arg)
12036059Samurai{
120436285Sbrian  if (!arg->prompt)
120536285Sbrian    log_Printf(LogWARN, "show: Cannot show without a prompt\n");
120636285Sbrian  else if (arg->argc > arg->argn)
120736285Sbrian    FindExec(arg->bundle, ShowCommands, arg->argc, arg->argn, arg->argv,
120836285Sbrian             arg->prompt, arg->cx);
12096059Samurai  else
121036285Sbrian    prompt_Printf(arg->prompt, "Use ``show ?'' to get a list.\n");
121126516Sbrian
121226516Sbrian  return 0;
12136059Samurai}
12146059Samurai
12156059Samuraistatic int
121631343SbrianTerminalCommand(struct cmdargs const *arg)
12176059Samurai{
121836285Sbrian  if (!arg->prompt) {
121936285Sbrian    log_Printf(LogWARN, "term: Need a prompt\n");
122026516Sbrian    return 1;
12216059Samurai  }
122236285Sbrian
122336285Sbrian  if (arg->cx->physical->link.lcp.fsm.state > ST_CLOSED) {
122436285Sbrian    prompt_Printf(arg->prompt, "LCP state is [%s]\n",
122536285Sbrian                  State2Nam(arg->cx->physical->link.lcp.fsm.state));
122636285Sbrian    return 1;
12276059Samurai  }
122836285Sbrian
122936285Sbrian  datalink_Up(arg->cx, 0, 0);
123036285Sbrian  prompt_TtyTermMode(arg->prompt, arg->cx);
123136285Sbrian  return 0;
12326059Samurai}
12336059Samurai
12346059Samuraistatic int
123531343SbrianQuitCommand(struct cmdargs const *arg)
12366059Samurai{
123736285Sbrian  if (!arg->prompt || prompt_IsController(arg->prompt) ||
123836285Sbrian      (arg->argc > arg->argn && !strcasecmp(arg->argv[arg->argn], "all") &&
123936285Sbrian       (arg->prompt->auth & LOCAL_AUTH)))
124036285Sbrian    Cleanup(EX_NORMAL);
124136285Sbrian  if (arg->prompt)
124236285Sbrian    prompt_Destroy(arg->prompt, 1);
124326516Sbrian
124426516Sbrian  return 0;
12456059Samurai}
12466059Samurai
12476059Samuraistatic int
124836285SbrianOpenCommand(struct cmdargs const *arg)
12496059Samurai{
125037160Sbrian  if (arg->argc == arg->argn)
125137993Sbrian    bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1);
125237160Sbrian  else if (arg->argc == arg->argn + 1) {
125337160Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp")) {
125437385Sbrian      struct datalink *cx = arg->cx ?
125537385Sbrian        arg->cx : bundle2datalink(arg->bundle, NULL);
125637385Sbrian      if (cx) {
125737385Sbrian        if (cx->physical->link.lcp.fsm.state == ST_OPENED)
125837385Sbrian          fsm_Reopen(&cx->physical->link.lcp.fsm);
125937160Sbrian        else
126037993Sbrian          bundle_Open(arg->bundle, cx->name, PHYS_ALL, 1);
126137160Sbrian      } else
126237160Sbrian        log_Printf(LogWARN, "open lcp: You must specify a link\n");
126337160Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) {
126437160Sbrian      struct fsm *fp;
12656059Samurai
126637210Sbrian      fp = &command_ChooseLink(arg)->ccp.fsm;
126737160Sbrian      if (fp->link->lcp.fsm.state != ST_OPENED)
126837160Sbrian        log_Printf(LogWARN, "open: LCP must be open before opening CCP\n");
126937160Sbrian      else if (fp->state == ST_OPENED)
127037160Sbrian        fsm_Reopen(fp);
127137160Sbrian      else {
127237160Sbrian        fp->open_mode = 0;	/* Not passive any more */
127337160Sbrian        if (fp->state == ST_STOPPED) {
127437160Sbrian          fsm_Down(fp);
127537160Sbrian          fsm_Up(fp);
127637160Sbrian        } else {
127737160Sbrian          fsm_Up(fp);
127837160Sbrian          fsm_Open(fp);
127937160Sbrian        }
128036285Sbrian      }
128137160Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ipcp")) {
128237160Sbrian      if (arg->cx)
128337160Sbrian        log_Printf(LogWARN, "open ipcp: You need not specify a link\n");
128437160Sbrian      if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED)
128537160Sbrian        fsm_Reopen(&arg->bundle->ncp.ipcp.fsm);
128637160Sbrian      else
128737993Sbrian        bundle_Open(arg->bundle, NULL, PHYS_ALL, 1);
128837160Sbrian    } else
128937160Sbrian      return -1;
129036285Sbrian  } else
129136285Sbrian    return -1;
129236285Sbrian
129326516Sbrian  return 0;
12946059Samurai}
12956059Samurai
129625067Sbrianstatic int
129736285SbrianCloseCommand(struct cmdargs const *arg)
12986059Samurai{
129937007Sbrian  if (arg->argc == arg->argn)
130037007Sbrian    bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_STAYDOWN);
130137007Sbrian  else if (arg->argc == arg->argn + 1) {
130237007Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp"))
130337007Sbrian      bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_LCP);
130437007Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "ccp") ||
130537007Sbrian             !strcasecmp(arg->argv[arg->argn], "ccp!")) {
130637007Sbrian      struct fsm *fp;
13076059Samurai
130837210Sbrian      fp = &command_ChooseLink(arg)->ccp.fsm;
130937007Sbrian      if (fp->state == ST_OPENED) {
131037007Sbrian        fsm_Close(fp);
131137007Sbrian        if (arg->argv[arg->argn][3] == '!')
131237007Sbrian          fp->open_mode = 0;		/* Stay ST_CLOSED */
131337007Sbrian        else
131437007Sbrian          fp->open_mode = OPEN_PASSIVE;	/* Wait for the peer to start */
131537007Sbrian      }
131637007Sbrian    } else
131736285Sbrian      return -1;
131836285Sbrian  } else
131936285Sbrian    return -1;
132036285Sbrian
132136285Sbrian  return 0;
13226059Samurai}
13236059Samurai
132425067Sbrianstatic int
132536285SbrianDownCommand(struct cmdargs const *arg)
132611336Samurai{
132737018Sbrian  if (arg->argc == arg->argn) {
132837018Sbrian      if (arg->cx)
132937018Sbrian        datalink_Down(arg->cx, CLOSE_STAYDOWN);
133037018Sbrian      else
133137018Sbrian        bundle_Down(arg->bundle, CLOSE_STAYDOWN);
133237018Sbrian  } else if (arg->argc == arg->argn + 1) {
133337018Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp")) {
133437018Sbrian      if (arg->cx)
133537018Sbrian        datalink_Down(arg->cx, CLOSE_LCP);
133637018Sbrian      else
133737018Sbrian        bundle_Down(arg->bundle, CLOSE_LCP);
133837018Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) {
133937018Sbrian      struct fsm *fp = arg->cx ? &arg->cx->physical->link.ccp.fsm :
134037018Sbrian                                 &arg->bundle->ncp.mp.link.ccp.fsm;
134137060Sbrian      fsm2initial(fp);
134237018Sbrian    } else
134337018Sbrian      return -1;
134436285Sbrian  } else
134536285Sbrian    return -1;
134636285Sbrian
134736285Sbrian  return 0;
134825067Sbrian}
134925067Sbrian
135025067Sbrianstatic int
135136285SbrianSetModemSpeed(struct cmdargs const *arg)
135225067Sbrian{
135336285Sbrian  long speed;
135436285Sbrian  char *end;
135511336Samurai
135636285Sbrian  if (arg->argc > arg->argn && *arg->argv[arg->argn]) {
135736285Sbrian    if (arg->argc > arg->argn+1) {
135854917Sbrian      log_Printf(LogWARN, "SetModemSpeed: Too many arguments\n");
135936285Sbrian      return -1;
136011336Samurai    }
136136285Sbrian    if (strcasecmp(arg->argv[arg->argn], "sync") == 0) {
136236285Sbrian      physical_SetSync(arg->cx->physical);
136336285Sbrian      return 0;
136436285Sbrian    }
136536285Sbrian    end = NULL;
136636285Sbrian    speed = strtol(arg->argv[arg->argn], &end, 10);
136736285Sbrian    if (*end) {
136836285Sbrian      log_Printf(LogWARN, "SetModemSpeed: Bad argument \"%s\"",
136936285Sbrian                arg->argv[arg->argn]);
137036285Sbrian      return -1;
137136285Sbrian    }
137236285Sbrian    if (physical_SetSpeed(arg->cx->physical, speed))
137336285Sbrian      return 0;
137436285Sbrian    log_Printf(LogWARN, "%s: Invalid speed\n", arg->argv[arg->argn]);
137536285Sbrian  } else
137636285Sbrian    log_Printf(LogWARN, "SetModemSpeed: No speed specified\n");
137724939Sbrian
137826516Sbrian  return -1;
137911336Samurai}
138011336Samurai
138125067Sbrianstatic int
138231343SbrianSetStoppedTimeout(struct cmdargs const *arg)
138328327Sbrian{
138436285Sbrian  struct link *l = &arg->cx->physical->link;
138536285Sbrian
138636285Sbrian  l->lcp.fsm.StoppedTimer.load = 0;
138736285Sbrian  l->ccp.fsm.StoppedTimer.load = 0;
138836285Sbrian  if (arg->argc <= arg->argn+2) {
138936285Sbrian    if (arg->argc > arg->argn) {
139036285Sbrian      l->lcp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn]) * SECTICKS;
139136285Sbrian      if (arg->argc > arg->argn+1)
139236285Sbrian        l->ccp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn+1]) * SECTICKS;
139328461Sbrian    }
139428327Sbrian    return 0;
139528327Sbrian  }
139628327Sbrian  return -1;
139728327Sbrian}
139828327Sbrian
139928327Sbrianstatic int
140031343SbrianSetServer(struct cmdargs const *arg)
140126940Sbrian{
140226940Sbrian  int res = -1;
140326940Sbrian
140436285Sbrian  if (arg->argc > arg->argn && arg->argc < arg->argn+4) {
140531081Sbrian    const char *port, *passwd, *mask;
140653125Sbrian    int mlen;
140731081Sbrian
140831081Sbrian    /* What's what ? */
140936285Sbrian    port = arg->argv[arg->argn];
141036285Sbrian    if (arg->argc == arg->argn + 2) {
141136285Sbrian      passwd = arg->argv[arg->argn+1];
141236285Sbrian      mask = NULL;
141336285Sbrian    } else if (arg->argc == arg->argn + 3) {
141436285Sbrian      passwd = arg->argv[arg->argn+1];
141536285Sbrian      mask = arg->argv[arg->argn+2];
141653125Sbrian      mlen = strlen(mask);
141753125Sbrian      if (mlen == 0 || mlen > 4 || strspn(mask, "01234567") != mlen ||
141853125Sbrian          (mlen == 4 && *mask != '0')) {
141953125Sbrian        log_Printf(LogWARN, "%s %s: %s: Invalid mask\n",
142053125Sbrian                   arg->argv[arg->argn - 2], arg->argv[arg->argn - 1], mask);
142131081Sbrian        return -1;
142253125Sbrian      }
142371764Sbrian    } else if (arg->argc != arg->argn + 1)
142471764Sbrian      return -1;
142571764Sbrian    else if (strcasecmp(port, "none") == 0) {
142671657Sbrian      if (server_Clear(arg->bundle))
142771657Sbrian        log_Printf(LogPHASE, "Disabled server socket\n");
142871657Sbrian      return 0;
142971657Sbrian    } else if (strcasecmp(port, "open") == 0) {
143071657Sbrian      switch (server_Reopen(arg->bundle)) {
143171657Sbrian        case SERVER_OK:
143271657Sbrian          return 0;
143371657Sbrian        case SERVER_FAILED:
143471764Sbrian          log_Printf(LogWARN, "Failed to reopen server port\n");
143571657Sbrian          return 1;
143671657Sbrian        case SERVER_UNSET:
143771764Sbrian          log_Printf(LogWARN, "Cannot reopen unset server socket\n");
143871657Sbrian          return 1;
143971657Sbrian        default:
144071657Sbrian          break;
144171657Sbrian      }
144271657Sbrian      return -1;
144371657Sbrian    } else if (strcasecmp(port, "closed") == 0) {
144436285Sbrian      if (server_Close(arg->bundle))
144571657Sbrian        log_Printf(LogPHASE, "Closed server socket\n");
144671657Sbrian      else
144771657Sbrian        log_Printf(LogWARN, "Server socket not open\n");
144871657Sbrian
144936285Sbrian      return 0;
145031081Sbrian    } else
145136285Sbrian      return -1;
145231081Sbrian
145371657Sbrian    strncpy(server.cfg.passwd, passwd, sizeof server.cfg.passwd - 1);
145471657Sbrian    server.cfg.passwd[sizeof server.cfg.passwd - 1] = '\0';
145531081Sbrian
145636285Sbrian    if (*port == '/') {
145731081Sbrian      mode_t imask;
145836285Sbrian      char *ptr, name[LINE_LEN + 12];
145928679Sbrian
146053125Sbrian      if (mask == NULL)
146131081Sbrian        imask = (mode_t)-1;
146253125Sbrian      else for (imask = mlen = 0; mask[mlen]; mlen++)
146353125Sbrian        imask = (imask * 8) + mask[mlen] - '0';
146436285Sbrian
146536285Sbrian      ptr = strstr(port, "%d");
146636285Sbrian      if (ptr) {
146736285Sbrian        snprintf(name, sizeof name, "%.*s%d%s",
146837210Sbrian                 (int)(ptr - port), port, arg->bundle->unit, ptr + 2);
146936285Sbrian        port = name;
147036285Sbrian      }
147136285Sbrian      res = server_LocalOpen(arg->bundle, port, imask);
147227346Sbrian    } else {
147336285Sbrian      int iport, add = 0;
147428679Sbrian
147531081Sbrian      if (mask != NULL)
147631081Sbrian        return -1;
147728679Sbrian
147836285Sbrian      if (*port == '+') {
147936285Sbrian        port++;
148036285Sbrian        add = 1;
148136285Sbrian      }
148231081Sbrian      if (strspn(port, "0123456789") != strlen(port)) {
148331081Sbrian        struct servent *s;
148431081Sbrian
148531081Sbrian        if ((s = getservbyname(port, "tcp")) == NULL) {
148631081Sbrian	  iport = 0;
148736285Sbrian	  log_Printf(LogWARN, "%s: Invalid port or service\n", port);
148828679Sbrian	} else
148931081Sbrian	  iport = ntohs(s->s_port);
149027346Sbrian      } else
149131081Sbrian        iport = atoi(port);
149236285Sbrian
149336285Sbrian      if (iport) {
149436285Sbrian        if (add)
149536285Sbrian          iport += arg->bundle->unit;
149636285Sbrian        res = server_TcpOpen(arg->bundle, iport);
149736285Sbrian      } else
149836285Sbrian        res = -1;
149927346Sbrian    }
150031081Sbrian  }
150126940Sbrian
150226940Sbrian  return res;
150326940Sbrian}
150426940Sbrian
150526940Sbrianstatic int
150631343SbrianSetEscape(struct cmdargs const *arg)
15076059Samurai{
15086059Samurai  int code;
150936285Sbrian  int argc = arg->argc - arg->argn;
151036285Sbrian  char const *const *argv = arg->argv + arg->argn;
15116059Samurai
15126059Samurai  for (code = 0; code < 33; code++)
151336285Sbrian    arg->cx->physical->async.cfg.EscMap[code] = 0;
151431343Sbrian
15156059Samurai  while (argc-- > 0) {
15166059Samurai    sscanf(*argv++, "%x", &code);
15176059Samurai    code &= 0xff;
151836285Sbrian    arg->cx->physical->async.cfg.EscMap[code >> 3] |= (1 << (code & 7));
151936285Sbrian    arg->cx->physical->async.cfg.EscMap[32] = 1;
15206059Samurai  }
152126516Sbrian  return 0;
15226059Samurai}
15236059Samurai
15246059Samuraistatic int
152531343SbrianSetInterfaceAddr(struct cmdargs const *arg)
15266059Samurai{
152781634Sbrian  struct ncp *ncp = &arg->bundle->ncp;
152881634Sbrian  struct ncpaddr ncpaddr;
152932267Sbrian  const char *hisaddr;
153032267Sbrian
153140561Sbrian  if (arg->argc > arg->argn + 4)
153240561Sbrian    return -1;
153340561Sbrian
153432267Sbrian  hisaddr = NULL;
153581634Sbrian  memset(&ncp->ipcp.cfg.my_range, '\0', sizeof ncp->ipcp.cfg.my_range);
153681634Sbrian  memset(&ncp->ipcp.cfg.peer_range, '\0', sizeof ncp->ipcp.cfg.peer_range);
153781634Sbrian  ncp->ipcp.cfg.HaveTriggerAddress = 0;
153881634Sbrian  ncp->ipcp.cfg.netmask.s_addr = INADDR_ANY;
153981634Sbrian  iplist_reset(&ncp->ipcp.cfg.peer_list);
154028394Sbrian
154136285Sbrian  if (arg->argc > arg->argn) {
154281634Sbrian    if (!ncprange_aton(&ncp->ipcp.cfg.my_range, ncp, arg->argv[arg->argn]))
154328679Sbrian      return 1;
154436285Sbrian    if (arg->argc > arg->argn+1) {
154536285Sbrian      hisaddr = arg->argv[arg->argn+1];
154636285Sbrian      if (arg->argc > arg->argn+2) {
154781634Sbrian        ncp->ipcp.ifmask = ncp->ipcp.cfg.netmask =
154881634Sbrian          GetIpAddr(arg->argv[arg->argn+2]);
154936285Sbrian	if (arg->argc > arg->argn+3) {
155081634Sbrian	  ncp->ipcp.cfg.TriggerAddress = GetIpAddr(arg->argv[arg->argn+3]);
155181634Sbrian	  ncp->ipcp.cfg.HaveTriggerAddress = 1;
15529440Samurai	}
15536059Samurai      }
15546059Samurai    }
15556059Samurai  }
155628394Sbrian
155740561Sbrian  /* 0.0.0.0 means any address (0 bits) */
155881634Sbrian  ncpaddr_getip4(&ncpaddr, &ncp->ipcp.my_ip);
155981634Sbrian  ncprange_getaddr(&ncp->ipcp.cfg.my_range, &ncpaddr);
156081634Sbrian  if (ncp->ipcp.my_ip.s_addr == INADDR_ANY)
156181634Sbrian    ncprange_setwidth(&ncp->ipcp.cfg.my_range, 0);
156281634Sbrian  bundle_AdjustFilters(arg->bundle, &ncpaddr, NULL);
156336285Sbrian
156436285Sbrian  if (hisaddr && !ipcp_UseHisaddr(arg->bundle, hisaddr,
156536928Sbrian                                  arg->bundle->phys_type.all & PHYS_AUTO))
156632267Sbrian    return 4;
156731121Sbrian
156826516Sbrian  return 0;
15696059Samurai}
15706059Samurai
157118752Sjkhstatic int
157244305SbrianSetRetry(int argc, char const *const *argv, u_int *timeout, u_int *maxreq,
157344305Sbrian          u_int *maxtrm, int def)
157444305Sbrian{
157544305Sbrian  if (argc == 0) {
157644305Sbrian    *timeout = DEF_FSMRETRY;
157744305Sbrian    *maxreq = def;
157844305Sbrian    if (maxtrm != NULL)
157944305Sbrian      *maxtrm = def;
158044305Sbrian  } else {
158144305Sbrian    long l = atol(argv[0]);
158244305Sbrian
158344305Sbrian    if (l < MIN_FSMRETRY) {
158444305Sbrian      log_Printf(LogWARN, "%ld: Invalid FSM retry period - min %d\n",
158544305Sbrian                 l, MIN_FSMRETRY);
158644305Sbrian      return 1;
158744305Sbrian    } else
158844305Sbrian      *timeout = l;
158944305Sbrian
159044305Sbrian    if (argc > 1) {
159144305Sbrian      l = atol(argv[1]);
159244305Sbrian      if (l < 1) {
159344305Sbrian        log_Printf(LogWARN, "%ld: Invalid FSM REQ tries - changed to 1\n", l);
159444305Sbrian        l = 1;
159544305Sbrian      }
159644305Sbrian      *maxreq = l;
159744305Sbrian
159844305Sbrian      if (argc > 2 && maxtrm != NULL) {
159944305Sbrian        l = atol(argv[2]);
160044305Sbrian        if (l < 1) {
160144305Sbrian          log_Printf(LogWARN, "%ld: Invalid FSM TRM tries - changed to 1\n", l);
160244305Sbrian          l = 1;
160344305Sbrian        }
160444305Sbrian        *maxtrm = l;
160544305Sbrian      }
160644305Sbrian    }
160744305Sbrian  }
160844305Sbrian
160944305Sbrian  return 0;
161044305Sbrian}
161144305Sbrian
161244305Sbrianstatic int
161331343SbrianSetVariable(struct cmdargs const *arg)
16146059Samurai{
161537210Sbrian  long long_val, param = (long)arg->cmd->args;
161679119Sbrian  int mode, dummyint, f, first, res;
161778410Sbrian  u_short *change;
161831343Sbrian  const char *argp;
161936285Sbrian  struct datalink *cx = arg->cx;	/* LOCAL_CX uses this */
162036285Sbrian  struct link *l = command_ChooseLink(arg);	/* LOCAL_CX_OPT uses this */
162181634Sbrian  struct in_addr *ipaddr;
162281634Sbrian  struct ncpaddr ncpaddr[2];
16236059Samurai
162436285Sbrian  if (arg->argc > arg->argn)
162536285Sbrian    argp = arg->argv[arg->argn];
162626551Sbrian  else
162731343Sbrian    argp = "";
162826551Sbrian
162979119Sbrian  res = 0;
163079119Sbrian
163136285Sbrian  if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
163236285Sbrian    log_Printf(LogWARN, "set %s: No context (use the `link' command)\n",
163336285Sbrian              arg->cmd->name);
163436285Sbrian    return 1;
163536285Sbrian  } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
163636285Sbrian    log_Printf(LogWARN, "set %s: Redundant context (%s) ignored\n",
163736285Sbrian              arg->cmd->name, cx->name);
163836285Sbrian    cx = NULL;
163936285Sbrian  }
164036285Sbrian
164126551Sbrian  switch (param) {
164228679Sbrian  case VAR_AUTHKEY:
164350139Sbrian    strncpy(arg->bundle->cfg.auth.key, argp,
164450139Sbrian            sizeof arg->bundle->cfg.auth.key - 1);
164550139Sbrian    arg->bundle->cfg.auth.key[sizeof arg->bundle->cfg.auth.key - 1] = '\0';
164628679Sbrian    break;
164737210Sbrian
164828679Sbrian  case VAR_AUTHNAME:
164940622Sbrian    switch (bundle_Phase(arg->bundle)) {
165058880Sbrian      default:
165158880Sbrian        log_Printf(LogWARN, "Altering authname while at phase %s\n",
165258880Sbrian                   bundle_PhaseName(arg->bundle));
165358880Sbrian        /* drop through */
165440622Sbrian      case PHASE_DEAD:
165540622Sbrian      case PHASE_ESTABLISH:
165640622Sbrian        strncpy(arg->bundle->cfg.auth.name, argp,
165740622Sbrian                sizeof arg->bundle->cfg.auth.name - 1);
165840622Sbrian        arg->bundle->cfg.auth.name[sizeof arg->bundle->cfg.auth.name-1] = '\0';
165940622Sbrian        break;
166036285Sbrian    }
166128679Sbrian    break;
166237210Sbrian
166336285Sbrian  case VAR_AUTOLOAD:
166449434Sbrian    if (arg->argc == arg->argn + 3) {
166549434Sbrian      int v1, v2, v3;
166649434Sbrian      char *end;
166749434Sbrian
166849434Sbrian      v1 = strtol(arg->argv[arg->argn], &end, 0);
166949434Sbrian      if (v1 < 0 || *end) {
167049434Sbrian        log_Printf(LogWARN, "autoload: %s: Invalid min percentage\n",
167149434Sbrian                   arg->argv[arg->argn]);
167279119Sbrian        res = 1;
167379119Sbrian        break;
167436285Sbrian      }
167549434Sbrian
167649434Sbrian      v2 = strtol(arg->argv[arg->argn + 1], &end, 0);
167749434Sbrian      if (v2 < 0 || *end) {
167849434Sbrian        log_Printf(LogWARN, "autoload: %s: Invalid max percentage\n",
167949434Sbrian                   arg->argv[arg->argn + 1]);
168079119Sbrian        res = 1;
168179119Sbrian        break;
168249434Sbrian      }
168349434Sbrian      if (v2 < v1) {
168449434Sbrian        v3 = v1;
168549434Sbrian        v1 = v2;
168649434Sbrian        v2 = v3;
168749434Sbrian      }
168849434Sbrian
168949434Sbrian      v3 = strtol(arg->argv[arg->argn + 2], &end, 0);
169049434Sbrian      if (v3 <= 0 || *end) {
169149434Sbrian        log_Printf(LogWARN, "autoload: %s: Invalid throughput period\n",
169249434Sbrian                   arg->argv[arg->argn + 2]);
169379119Sbrian        res = 1;
169479119Sbrian        break;
169549434Sbrian      }
169649434Sbrian
169749434Sbrian      arg->bundle->ncp.mp.cfg.autoload.min = v1;
169849434Sbrian      arg->bundle->ncp.mp.cfg.autoload.max = v2;
169949434Sbrian      arg->bundle->ncp.mp.cfg.autoload.period = v3;
170049434Sbrian      mp_RestartAutoloadTimer(&arg->bundle->ncp.mp);
170136285Sbrian    } else {
170279119Sbrian      log_Printf(LogWARN, "Set autoload requires three arguments\n");
170379119Sbrian      res = 1;
170436285Sbrian    }
170536285Sbrian    break;
170637210Sbrian
170728679Sbrian  case VAR_DIAL:
170836285Sbrian    strncpy(cx->cfg.script.dial, argp, sizeof cx->cfg.script.dial - 1);
170936285Sbrian    cx->cfg.script.dial[sizeof cx->cfg.script.dial - 1] = '\0';
171028679Sbrian    break;
171137210Sbrian
171228679Sbrian  case VAR_LOGIN:
171336285Sbrian    strncpy(cx->cfg.script.login, argp, sizeof cx->cfg.script.login - 1);
171436285Sbrian    cx->cfg.script.login[sizeof cx->cfg.script.login - 1] = '\0';
171528679Sbrian    break;
171637210Sbrian
171736285Sbrian  case VAR_WINSIZE:
171836285Sbrian    if (arg->argc > arg->argn) {
171936285Sbrian      l->ccp.cfg.deflate.out.winsize = atoi(arg->argv[arg->argn]);
172036285Sbrian      if (l->ccp.cfg.deflate.out.winsize < 8 ||
172136285Sbrian          l->ccp.cfg.deflate.out.winsize > 15) {
172236285Sbrian          log_Printf(LogWARN, "%d: Invalid outgoing window size\n",
172336285Sbrian                    l->ccp.cfg.deflate.out.winsize);
172436285Sbrian          l->ccp.cfg.deflate.out.winsize = 15;
172536285Sbrian      }
172636285Sbrian      if (arg->argc > arg->argn+1) {
172736285Sbrian        l->ccp.cfg.deflate.in.winsize = atoi(arg->argv[arg->argn+1]);
172836285Sbrian        if (l->ccp.cfg.deflate.in.winsize < 8 ||
172936285Sbrian            l->ccp.cfg.deflate.in.winsize > 15) {
173036285Sbrian            log_Printf(LogWARN, "%d: Invalid incoming window size\n",
173136285Sbrian                      l->ccp.cfg.deflate.in.winsize);
173236285Sbrian            l->ccp.cfg.deflate.in.winsize = 15;
173336285Sbrian        }
173436285Sbrian      } else
173536285Sbrian        l->ccp.cfg.deflate.in.winsize = 0;
173636285Sbrian    } else {
173779119Sbrian      log_Printf(LogWARN, "No window size specified\n");
173879119Sbrian      res = 1;
173936285Sbrian    }
174036285Sbrian    break;
174137210Sbrian
174293418Sbrian#ifndef NODES
174378411Sbrian  case VAR_MPPE:
174479119Sbrian    if (arg->argc > arg->argn + 2) {
174579119Sbrian      res = -1;
174679119Sbrian      break;
174779119Sbrian    }
174878411Sbrian
174978411Sbrian    if (arg->argc == arg->argn) {
175078411Sbrian      l->ccp.cfg.mppe.keybits = 0;
175178411Sbrian      l->ccp.cfg.mppe.state = MPPE_ANYSTATE;
175278411Sbrian      l->ccp.cfg.mppe.required = 0;
175378411Sbrian      break;
175478411Sbrian    }
175578411Sbrian
175678411Sbrian    if (!strcmp(argp, "*"))
175778411Sbrian      long_val = 0;
175878411Sbrian    else {
175978411Sbrian      long_val = atol(argp);
176078411Sbrian      if (long_val != 40 && long_val != 56 && long_val != 128) {
176178411Sbrian        log_Printf(LogWARN, "%s: Invalid bits value\n", argp);
176279119Sbrian        res = -1;
176379119Sbrian        break;
176467910Sbrian      }
176567910Sbrian    }
176678411Sbrian
176778411Sbrian    if (arg->argc == arg->argn + 2) {
176878411Sbrian      if (!strcmp(arg->argv[arg->argn + 1], "*"))
176978411Sbrian        l->ccp.cfg.mppe.state = MPPE_ANYSTATE;
177078411Sbrian      else if (!strcasecmp(arg->argv[arg->argn + 1], "stateless"))
177178411Sbrian        l->ccp.cfg.mppe.state = MPPE_STATELESS;
177279370Sbrian      else if (!strcasecmp(arg->argv[arg->argn + 1], "stateful"))
177378411Sbrian        l->ccp.cfg.mppe.state = MPPE_STATEFUL;
177478411Sbrian      else {
177578411Sbrian        log_Printf(LogWARN, "%s: Invalid state value\n",
177678411Sbrian                   arg->argv[arg->argn + 1]);
177779119Sbrian        res = -1;
177879119Sbrian        break;
177978411Sbrian      }
178078411Sbrian    } else
178178411Sbrian      l->ccp.cfg.mppe.state = MPPE_ANYSTATE;
178278411Sbrian    l->ccp.cfg.mppe.keybits = long_val;
178378411Sbrian    l->ccp.cfg.mppe.required = 1;
178467910Sbrian    break;
178567910Sbrian#endif
178667910Sbrian
178728679Sbrian  case VAR_DEVICE:
178836285Sbrian    physical_SetDeviceList(cx->physical, arg->argc - arg->argn,
178936285Sbrian                           arg->argv + arg->argn);
179036285Sbrian    break;
179137210Sbrian
179236285Sbrian  case VAR_ACCMAP:
179336285Sbrian    if (arg->argc > arg->argn) {
179437210Sbrian      u_long ulong_val;
179536285Sbrian      sscanf(argp, "%lx", &ulong_val);
179637210Sbrian      cx->physical->link.lcp.cfg.accmap = (u_int32_t)ulong_val;
179736285Sbrian    } else {
179879119Sbrian      log_Printf(LogWARN, "No accmap specified\n");
179979119Sbrian      res = 1;
180036285Sbrian    }
180136285Sbrian    break;
180237210Sbrian
180336285Sbrian  case VAR_MODE:
180436285Sbrian    mode = Nam2mode(argp);
180536285Sbrian    if (mode == PHYS_NONE || mode == PHYS_ALL) {
180636285Sbrian      log_Printf(LogWARN, "%s: Invalid mode\n", argp);
180779119Sbrian      res = -1;
180879119Sbrian      break;
180936285Sbrian    }
181036285Sbrian    bundle_SetMode(arg->bundle, cx, mode);
181136285Sbrian    break;
181237210Sbrian
181336285Sbrian  case VAR_MRRU:
181440622Sbrian    switch (bundle_Phase(arg->bundle)) {
181540622Sbrian      case PHASE_DEAD:
181640622Sbrian        break;
181740622Sbrian      case PHASE_ESTABLISH:
181840622Sbrian        /* Make sure none of our links are DATALINK_LCP or greater */
181940622Sbrian        if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) {
182040622Sbrian          log_Printf(LogWARN, "mrru: Only changable before LCP negotiations\n");
182179119Sbrian          res = 1;
182279119Sbrian          break;
182340622Sbrian        }
182440622Sbrian        break;
182540622Sbrian      default:
182640622Sbrian        log_Printf(LogWARN, "mrru: Only changable at phase DEAD/ESTABLISH\n");
182779119Sbrian        res = 1;
182879119Sbrian        break;
182929696Sbrian    }
183079119Sbrian    if (res != 0)
183179119Sbrian      break;
183237210Sbrian    long_val = atol(argp);
183337210Sbrian    if (long_val && long_val < MIN_MRU) {
183437210Sbrian      log_Printf(LogWARN, "MRRU %ld: too small - min %d\n", long_val, MIN_MRU);
183579119Sbrian      res = 1;
183679119Sbrian      break;
183737210Sbrian    } else if (long_val > MAX_MRU) {
183837210Sbrian      log_Printf(LogWARN, "MRRU %ld: too big - max %d\n", long_val, MAX_MRU);
183979119Sbrian      res = 1;
184079119Sbrian      break;
184137210Sbrian    } else
184237210Sbrian      arg->bundle->ncp.mp.cfg.mrru = long_val;
184328679Sbrian    break;
184437210Sbrian
184536285Sbrian  case VAR_MRU:
184679163Sbrian    long_val = 0;	/* silence gcc */
184779163Sbrian    change = NULL;	/* silence gcc */
184878410Sbrian    switch(arg->argc - arg->argn) {
184978410Sbrian    case 1:
185079119Sbrian      if (argp[strspn(argp, "0123456789")] != '\0') {
185179119Sbrian        res = -1;
185279119Sbrian        break;
185379119Sbrian      }
185479119Sbrian      /*FALLTHRU*/
185578410Sbrian    case 0:
185678410Sbrian      long_val = atol(argp);
185778410Sbrian      change = &l->lcp.cfg.mru;
185878410Sbrian      if (long_val > l->lcp.cfg.max_mru) {
185978410Sbrian        log_Printf(LogWARN, "MRU %ld: too large - max set to %d\n", long_val,
186078410Sbrian                   l->lcp.cfg.max_mru);
186179119Sbrian        res = 1;
186279119Sbrian        break;
186378410Sbrian      }
186478410Sbrian      break;
186578410Sbrian    case 2:
186679119Sbrian      if (strcasecmp(argp, "max") && strcasecmp(argp, "maximum")) {
186779119Sbrian        res = -1;
186879119Sbrian        break;
186979119Sbrian      }
187078410Sbrian      long_val = atol(arg->argv[arg->argn + 1]);
187178410Sbrian      change = &l->lcp.cfg.max_mru;
187278410Sbrian      if (long_val > MAX_MRU) {
187378410Sbrian        log_Printf(LogWARN, "MRU %ld: too large - maximum is %d\n", long_val,
187478410Sbrian                   MAX_MRU);
187579119Sbrian        res = 1;
187679119Sbrian        break;
187778410Sbrian      }
187878410Sbrian      break;
187978410Sbrian    default:
188079119Sbrian      res = -1;
188179119Sbrian      break;
188278410Sbrian    }
188379119Sbrian    if (res != 0)
188479119Sbrian      break;
188578410Sbrian
188637210Sbrian    if (long_val == 0)
188780385Sbrian      *change = 0;
188837210Sbrian    else if (long_val < MIN_MRU) {
188937210Sbrian      log_Printf(LogWARN, "MRU %ld: too small - min %d\n", long_val, MIN_MRU);
189079119Sbrian      res = 1;
189179119Sbrian      break;
189237210Sbrian    } else if (long_val > MAX_MRU) {
189337210Sbrian      log_Printf(LogWARN, "MRU %ld: too big - max %d\n", long_val, MAX_MRU);
189479119Sbrian      res = 1;
189579119Sbrian      break;
189637210Sbrian    } else
189778410Sbrian      *change = long_val;
189878410Sbrian    if (l->lcp.cfg.mru > *change)
189978410Sbrian      l->lcp.cfg.mru = *change;
190028679Sbrian    break;
190137210Sbrian
190236285Sbrian  case VAR_MTU:
190379163Sbrian    long_val = 0;	/* silence gcc */
190479163Sbrian    change = NULL;	/* silence gcc */
190578410Sbrian    switch(arg->argc - arg->argn) {
190678410Sbrian    case 1:
190779119Sbrian      if (argp[strspn(argp, "0123456789")] != '\0') {
190879119Sbrian        res = -1;
190979119Sbrian        break;
191079119Sbrian      }
191179119Sbrian      /*FALLTHRU*/
191278410Sbrian    case 0:
191378410Sbrian      long_val = atol(argp);
191478410Sbrian      change = &l->lcp.cfg.mtu;
191578410Sbrian      if (long_val > l->lcp.cfg.max_mtu) {
191678410Sbrian        log_Printf(LogWARN, "MTU %ld: too large - max set to %d\n", long_val,
191778410Sbrian                   l->lcp.cfg.max_mtu);
191879119Sbrian        res = 1;
191979119Sbrian        break;
192078410Sbrian      }
192178410Sbrian      break;
192278410Sbrian    case 2:
192379119Sbrian      if (strcasecmp(argp, "max") && strcasecmp(argp, "maximum")) {
192479119Sbrian        res = -1;
192579119Sbrian        break;
192679119Sbrian      }
192778410Sbrian      long_val = atol(arg->argv[arg->argn + 1]);
192878410Sbrian      change = &l->lcp.cfg.max_mtu;
192978410Sbrian      if (long_val > MAX_MTU) {
193078410Sbrian        log_Printf(LogWARN, "MTU %ld: too large - maximum is %d\n", long_val,
193178410Sbrian                   MAX_MTU);
193279119Sbrian        res = 1;
193379119Sbrian        break;
193478410Sbrian      }
193578410Sbrian      break;
193678410Sbrian    default:
193779119Sbrian      res = -1;
193879119Sbrian      break;
193978410Sbrian    }
194078410Sbrian
194179119Sbrian    if (res != 0)
194279119Sbrian      break;
194379119Sbrian
194437210Sbrian    if (long_val && long_val < MIN_MTU) {
194537210Sbrian      log_Printf(LogWARN, "MTU %ld: too small - min %d\n", long_val, MIN_MTU);
194679119Sbrian      res = 1;
194779119Sbrian      break;
194837210Sbrian    } else if (long_val > MAX_MTU) {
194937210Sbrian      log_Printf(LogWARN, "MTU %ld: too big - max %d\n", long_val, MAX_MTU);
195079119Sbrian      res = 1;
195179119Sbrian      break;
195237210Sbrian    } else
195378410Sbrian      *change = long_val;
195478410Sbrian    if (l->lcp.cfg.mtu > *change)
195578410Sbrian      l->lcp.cfg.mtu = *change;
195636285Sbrian    break;
195737210Sbrian
195836285Sbrian  case VAR_OPENMODE:
195936285Sbrian    if (strcasecmp(argp, "active") == 0)
196036285Sbrian      cx->physical->link.lcp.cfg.openmode = arg->argc > arg->argn+1 ?
196136285Sbrian        atoi(arg->argv[arg->argn+1]) : 1;
196236285Sbrian    else if (strcasecmp(argp, "passive") == 0)
196336285Sbrian      cx->physical->link.lcp.cfg.openmode = OPEN_PASSIVE;
196436285Sbrian    else {
196579119Sbrian      log_Printf(LogWARN, "%s: Invalid openmode\n", argp);
196679119Sbrian      res = 1;
196736285Sbrian    }
196836285Sbrian    break;
196937210Sbrian
197028679Sbrian  case VAR_PHONE:
197136285Sbrian    strncpy(cx->cfg.phone.list, argp, sizeof cx->cfg.phone.list - 1);
197236285Sbrian    cx->cfg.phone.list[sizeof cx->cfg.phone.list - 1] = '\0';
197338174Sbrian    cx->phone.alt = cx->phone.next = NULL;
197428679Sbrian    break;
197537210Sbrian
197628679Sbrian  case VAR_HANGUP:
197736285Sbrian    strncpy(cx->cfg.script.hangup, argp, sizeof cx->cfg.script.hangup - 1);
197836285Sbrian    cx->cfg.script.hangup[sizeof cx->cfg.script.hangup - 1] = '\0';
197928679Sbrian    break;
198037210Sbrian
198161534Sbrian  case VAR_IFQUEUE:
198261534Sbrian    long_val = atol(argp);
198361534Sbrian    arg->bundle->cfg.ifqueue = long_val < 0 ? 0 : long_val;
198461534Sbrian    break;
198561534Sbrian
198652488Sbrian  case VAR_LOGOUT:
198752488Sbrian    strncpy(cx->cfg.script.logout, argp, sizeof cx->cfg.script.logout - 1);
198852488Sbrian    cx->cfg.script.logout[sizeof cx->cfg.script.logout - 1] = '\0';
198952488Sbrian    break;
199052488Sbrian
199136285Sbrian  case VAR_IDLETIMEOUT:
199279119Sbrian    if (arg->argc > arg->argn+2) {
199379119Sbrian      log_Printf(LogWARN, "Too many idle timeout values\n");
199479119Sbrian      res = 1;
199579119Sbrian    } else if (arg->argc == arg->argn) {
199679119Sbrian      log_Printf(LogWARN, "Too few idle timeout values\n");
199779119Sbrian      res = 1;
199879119Sbrian    } else {
199949978Sbrian      int timeout, min;
200049978Sbrian
200149978Sbrian      timeout = atoi(argp);
200249978Sbrian      min = arg->argc == arg->argn + 2 ? atoi(arg->argv[arg->argn + 1]) : -1;
200349978Sbrian      bundle_SetIdleTimer(arg->bundle, timeout, min);
200449978Sbrian    }
200529549Sbrian    break;
200637210Sbrian
200736285Sbrian  case VAR_LQRPERIOD:
200837210Sbrian    long_val = atol(argp);
200937210Sbrian    if (long_val < MIN_LQRPERIOD) {
201037210Sbrian      log_Printf(LogWARN, "%ld: Invalid lqr period - min %d\n",
201137210Sbrian                 long_val, MIN_LQRPERIOD);
201279119Sbrian      res = 1;
201336285Sbrian    } else
201437210Sbrian      l->lcp.cfg.lqrperiod = long_val;
201536285Sbrian    break;
201637210Sbrian
201736285Sbrian  case VAR_LCPRETRY:
201879119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
201979119Sbrian                   &cx->physical->link.lcp.cfg.fsm.timeout,
202079119Sbrian                   &cx->physical->link.lcp.cfg.fsm.maxreq,
202179119Sbrian                   &cx->physical->link.lcp.cfg.fsm.maxtrm, DEF_FSMTRIES);
202236285Sbrian    break;
202337210Sbrian
202436285Sbrian  case VAR_CHAPRETRY:
202579119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
202679119Sbrian                   &cx->chap.auth.cfg.fsm.timeout,
202779119Sbrian                   &cx->chap.auth.cfg.fsm.maxreq, NULL, DEF_FSMAUTHTRIES);
202836285Sbrian    break;
202937210Sbrian
203036285Sbrian  case VAR_PAPRETRY:
203179119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
203279119Sbrian                   &cx->pap.cfg.fsm.timeout, &cx->pap.cfg.fsm.maxreq,
203379119Sbrian                   NULL, DEF_FSMAUTHTRIES);
203436285Sbrian    break;
203537210Sbrian
203636285Sbrian  case VAR_CCPRETRY:
203779119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
203879119Sbrian                   &l->ccp.cfg.fsm.timeout, &l->ccp.cfg.fsm.maxreq,
203979119Sbrian                   &l->ccp.cfg.fsm.maxtrm, DEF_FSMTRIES);
204036285Sbrian    break;
204137210Sbrian
204236285Sbrian  case VAR_IPCPRETRY:
204379119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
204479119Sbrian                   &arg->bundle->ncp.ipcp.cfg.fsm.timeout,
204579119Sbrian                   &arg->bundle->ncp.ipcp.cfg.fsm.maxreq,
204679119Sbrian                   &arg->bundle->ncp.ipcp.cfg.fsm.maxtrm, DEF_FSMTRIES);
204736285Sbrian    break;
204837210Sbrian
204936285Sbrian  case VAR_NBNS:
205036285Sbrian  case VAR_DNS:
205158044Sbrian    if (param == VAR_DNS) {
205281634Sbrian      ipaddr = arg->bundle->ncp.ipcp.cfg.ns.dns;
205381634Sbrian      ipaddr[0].s_addr = ipaddr[1].s_addr = INADDR_NONE;
205458044Sbrian    } else {
205581634Sbrian      ipaddr = arg->bundle->ncp.ipcp.cfg.ns.nbns;
205681634Sbrian      ipaddr[0].s_addr = ipaddr[1].s_addr = INADDR_ANY;
205758044Sbrian    }
205836285Sbrian
205936285Sbrian    if (arg->argc > arg->argn) {
206081634Sbrian      ncpaddr_aton(ncpaddr, &arg->bundle->ncp, arg->argv[arg->argn]);
206181634Sbrian      if (!ncpaddr_getip4(ncpaddr, ipaddr))
206281634Sbrian        return -1;
206381634Sbrian      if (arg->argc > arg->argn+1) {
206481634Sbrian        ncpaddr_aton(ncpaddr + 1, &arg->bundle->ncp, arg->argv[arg->argn + 1]);
206581634Sbrian        if (!ncpaddr_getip4(ncpaddr + 1, ipaddr + 1))
206681634Sbrian          return -1;
206781634Sbrian      }
206836285Sbrian
206981634Sbrian      if (ipaddr[0].s_addr == INADDR_ANY) {
207081634Sbrian        ipaddr[0] = ipaddr[1];
207181634Sbrian        ipaddr[1].s_addr = INADDR_ANY;
207258044Sbrian      }
207381634Sbrian      if (ipaddr[0].s_addr == INADDR_NONE) {
207481634Sbrian        ipaddr[0] = ipaddr[1];
207581634Sbrian        ipaddr[1].s_addr = INADDR_NONE;
207658044Sbrian      }
207736285Sbrian    }
207836285Sbrian    break;
207938174Sbrian
208038174Sbrian  case VAR_CALLBACK:
208138174Sbrian    cx->cfg.callback.opmask = 0;
208238174Sbrian    for (dummyint = arg->argn; dummyint < arg->argc; dummyint++) {
208338174Sbrian      if (!strcasecmp(arg->argv[dummyint], "auth"))
208438174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_AUTH);
208538174Sbrian      else if (!strcasecmp(arg->argv[dummyint], "cbcp"))
208638174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_CBCP);
208738174Sbrian      else if (!strcasecmp(arg->argv[dummyint], "e.164")) {
208838174Sbrian        if (dummyint == arg->argc - 1)
208938174Sbrian          log_Printf(LogWARN, "No E.164 arg (E.164 ignored) !\n");
209038174Sbrian        else {
209138174Sbrian          cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_E164);
209238174Sbrian          strncpy(cx->cfg.callback.msg, arg->argv[++dummyint],
209338174Sbrian                  sizeof cx->cfg.callback.msg - 1);
209438174Sbrian          cx->cfg.callback.msg[sizeof cx->cfg.callback.msg - 1] = '\0';
209538174Sbrian        }
209638174Sbrian      } else if (!strcasecmp(arg->argv[dummyint], "none"))
209738174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_NONE);
209879119Sbrian      else {
209979119Sbrian        res = -1;
210079119Sbrian        break;
210179119Sbrian      }
210238174Sbrian    }
210338174Sbrian    if (cx->cfg.callback.opmask == CALLBACK_BIT(CALLBACK_NONE))
210438174Sbrian      cx->cfg.callback.opmask = 0;
210538174Sbrian    break;
210638174Sbrian
210738174Sbrian  case VAR_CBCP:
210838174Sbrian    cx->cfg.cbcp.delay = 0;
210938174Sbrian    *cx->cfg.cbcp.phone = '\0';
211038174Sbrian    cx->cfg.cbcp.fsmretry = DEF_FSMRETRY;
211138174Sbrian    if (arg->argc > arg->argn) {
211238174Sbrian      strncpy(cx->cfg.cbcp.phone, arg->argv[arg->argn],
211338174Sbrian              sizeof cx->cfg.cbcp.phone - 1);
211438174Sbrian      cx->cfg.cbcp.phone[sizeof cx->cfg.cbcp.phone - 1] = '\0';
211538174Sbrian      if (arg->argc > arg->argn + 1) {
211638174Sbrian        cx->cfg.cbcp.delay = atoi(arg->argv[arg->argn + 1]);
211738174Sbrian        if (arg->argc > arg->argn + 2) {
211838174Sbrian          long_val = atol(arg->argv[arg->argn + 2]);
211938174Sbrian          if (long_val < MIN_FSMRETRY)
212038174Sbrian            log_Printf(LogWARN, "%ld: Invalid CBCP FSM retry period - min %d\n",
212138174Sbrian                       long_val, MIN_FSMRETRY);
212238174Sbrian          else
212338174Sbrian            cx->cfg.cbcp.fsmretry = long_val;
212438174Sbrian        }
212538174Sbrian      }
212638174Sbrian    }
212738174Sbrian    break;
212838544Sbrian
212938544Sbrian  case VAR_CHOKED:
213038544Sbrian    arg->bundle->cfg.choked.timeout = atoi(argp);
213138544Sbrian    if (arg->bundle->cfg.choked.timeout <= 0)
213238544Sbrian      arg->bundle->cfg.choked.timeout = CHOKED_TIMEOUT;
213338544Sbrian    break;
213440665Sbrian
213540665Sbrian  case VAR_SENDPIPE:
213640665Sbrian    long_val = atol(argp);
213781634Sbrian    arg->bundle->ncp.cfg.sendpipe = long_val;
213840665Sbrian    break;
213940665Sbrian
214040665Sbrian  case VAR_RECVPIPE:
214140665Sbrian    long_val = atol(argp);
214281634Sbrian    arg->bundle->ncp.cfg.recvpipe = long_val;
214340665Sbrian    break;
214443313Sbrian
214543313Sbrian#ifndef NORADIUS
214643313Sbrian  case VAR_RADIUS:
214743313Sbrian    if (!*argp)
214843313Sbrian      *arg->bundle->radius.cfg.file = '\0';
214943313Sbrian    else if (access(argp, R_OK)) {
215043313Sbrian      log_Printf(LogWARN, "%s: %s\n", argp, strerror(errno));
215179119Sbrian      res = 1;
215279119Sbrian      break;
215343313Sbrian    } else {
215443313Sbrian      strncpy(arg->bundle->radius.cfg.file, argp,
215543313Sbrian              sizeof arg->bundle->radius.cfg.file - 1);
215643313Sbrian      arg->bundle->radius.cfg.file
215743313Sbrian        [sizeof arg->bundle->radius.cfg.file - 1] = '\0';
215843313Sbrian    }
215943313Sbrian    break;
216043313Sbrian#endif
216144073Sbrian
216244073Sbrian  case VAR_CD:
216344073Sbrian    if (*argp) {
216451699Sbrian      if (strcasecmp(argp, "off")) {
216551699Sbrian        long_val = atol(argp);
216651699Sbrian        if (long_val < 0)
216751699Sbrian          long_val = 0;
216851699Sbrian        cx->physical->cfg.cd.delay = long_val;
216951699Sbrian        cx->physical->cfg.cd.necessity = argp[strlen(argp)-1] == '!' ?
217051699Sbrian          CD_REQUIRED : CD_VARIABLE;
217151699Sbrian      } else
217251699Sbrian        cx->physical->cfg.cd.necessity = CD_NOTREQUIRED;
217344073Sbrian    } else {
217453733Sbrian      cx->physical->cfg.cd.delay = 0;
217553733Sbrian      cx->physical->cfg.cd.necessity = CD_DEFAULT;
217644073Sbrian    }
217744073Sbrian    break;
217836285Sbrian
217946686Sbrian  case VAR_PARITY:
218046686Sbrian    if (arg->argc == arg->argn + 1)
218179119Sbrian      res = physical_SetParity(arg->cx->physical, argp);
218246686Sbrian    else {
218379119Sbrian      log_Printf(LogWARN, "Parity value must be odd, even or none\n");
218479119Sbrian      res = 1;
218546686Sbrian    }
218646686Sbrian    break;
21876059Samurai
218846686Sbrian  case VAR_CRTSCTS:
218946686Sbrian    if (strcasecmp(argp, "on") == 0)
219036285Sbrian      physical_SetRtsCts(arg->cx->physical, 1);
219146686Sbrian    else if (strcasecmp(argp, "off") == 0)
219236285Sbrian      physical_SetRtsCts(arg->cx->physical, 0);
219346686Sbrian    else {
219479119Sbrian      log_Printf(LogWARN, "RTS/CTS value must be on or off\n");
219579119Sbrian      res = 1;
219646686Sbrian    }
219746686Sbrian    break;
219850867Sbrian
219950867Sbrian  case VAR_URGENTPORTS:
220051048Sbrian    if (arg->argn == arg->argc) {
220181634Sbrian      ncp_SetUrgentTOS(&arg->bundle->ncp);
220281634Sbrian      ncp_ClearUrgentTcpPorts(&arg->bundle->ncp);
220381634Sbrian      ncp_ClearUrgentUdpPorts(&arg->bundle->ncp);
220451048Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "udp")) {
220581634Sbrian      ncp_SetUrgentTOS(&arg->bundle->ncp);
220651048Sbrian      if (arg->argn == arg->argc - 1)
220781634Sbrian        ncp_ClearUrgentUdpPorts(&arg->bundle->ncp);
220851048Sbrian      else for (f = arg->argn + 1; f < arg->argc; f++)
220951048Sbrian        if (*arg->argv[f] == '+')
221081634Sbrian          ncp_AddUrgentUdpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1));
221151048Sbrian        else if (*arg->argv[f] == '-')
221281634Sbrian          ncp_RemoveUrgentUdpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1));
221351048Sbrian        else {
221451048Sbrian          if (f == arg->argn)
221581634Sbrian            ncp_ClearUrgentUdpPorts(&arg->bundle->ncp);
221681634Sbrian          ncp_AddUrgentUdpPort(&arg->bundle->ncp, atoi(arg->argv[f]));
221751048Sbrian        }
221861430Sbrian    } else if (arg->argn == arg->argc - 1 &&
221961430Sbrian               !strcasecmp(arg->argv[arg->argn], "none")) {
222081634Sbrian      ncp_ClearUrgentTcpPorts(&arg->bundle->ncp);
222181634Sbrian      ncp_ClearUrgentUdpPorts(&arg->bundle->ncp);
222281634Sbrian      ncp_ClearUrgentTOS(&arg->bundle->ncp);
222351048Sbrian    } else {
222481634Sbrian      ncp_SetUrgentTOS(&arg->bundle->ncp);
222551048Sbrian      first = arg->argn;
222651048Sbrian      if (!strcasecmp(arg->argv[first], "tcp") && ++first == arg->argc)
222781634Sbrian        ncp_ClearUrgentTcpPorts(&arg->bundle->ncp);
222851048Sbrian
222951048Sbrian      for (f = first; f < arg->argc; f++)
223051048Sbrian        if (*arg->argv[f] == '+')
223181634Sbrian          ncp_AddUrgentTcpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1));
223251048Sbrian        else if (*arg->argv[f] == '-')
223381634Sbrian          ncp_RemoveUrgentTcpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1));
223451048Sbrian        else {
223551048Sbrian          if (f == first)
223681634Sbrian            ncp_ClearUrgentTcpPorts(&arg->bundle->ncp);
223781634Sbrian          ncp_AddUrgentTcpPort(&arg->bundle->ncp, atoi(arg->argv[f]));
223851048Sbrian        }
223951048Sbrian    }
224050867Sbrian    break;
224120812Sjkh  }
224246686Sbrian
224379119Sbrian  return res;
224420812Sjkh}
224520812Sjkh
224630715Sbrianstatic struct cmdtab const SetCommands[] = {
224736285Sbrian  {"accmap", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
224836285Sbrian  "accmap value", "set accmap hex-value", (const void *)VAR_ACCMAP},
224928679Sbrian  {"authkey", "key", SetVariable, LOCAL_AUTH,
225036285Sbrian  "authentication key", "set authkey|key key", (const void *)VAR_AUTHKEY},
225128679Sbrian  {"authname", NULL, SetVariable, LOCAL_AUTH,
225236285Sbrian  "authentication name", "set authname name", (const void *)VAR_AUTHNAME},
225336285Sbrian  {"autoload", NULL, SetVariable, LOCAL_AUTH,
225436285Sbrian  "auto link [de]activation", "set autoload maxtime maxload mintime minload",
225536285Sbrian  (const void *)VAR_AUTOLOAD},
225650867Sbrian  {"bandwidth", NULL, mp_SetDatalinkBandwidth, LOCAL_AUTH | LOCAL_CX,
225750867Sbrian  "datalink bandwidth", "set bandwidth value"},
225838174Sbrian  {"callback", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
225938174Sbrian  "callback control", "set callback [none|auth|cbcp|"
226038174Sbrian  "E.164 *|number[,number]...]...", (const void *)VAR_CALLBACK},
226138174Sbrian  {"cbcp", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
226238174Sbrian  "CBCP control", "set cbcp [*|phone[,phone...] [delay [timeout]]]",
226338174Sbrian  (const void *)VAR_CBCP},
226444305Sbrian  {"ccpretry", "ccpretries", SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
226544305Sbrian   "CCP retries", "set ccpretry value [attempts]", (const void *)VAR_CCPRETRY},
226644073Sbrian  {"cd", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "Carrier delay requirement",
226744073Sbrian   "set cd value[!]", (const void *)VAR_CD},
226844305Sbrian  {"chapretry", "chapretries", SetVariable, LOCAL_AUTH | LOCAL_CX,
226944305Sbrian   "CHAP retries", "set chapretry value [attempts]",
227044305Sbrian   (const void *)VAR_CHAPRETRY},
227138544Sbrian  {"choked", NULL, SetVariable, LOCAL_AUTH,
227238544Sbrian  "choked timeout", "set choked [secs]", (const void *)VAR_CHOKED},
227346686Sbrian  {"ctsrts", "crtscts", SetVariable, LOCAL_AUTH | LOCAL_CX,
227446686Sbrian   "Use hardware flow control", "set ctsrts [on|off]",
227546686Sbrian   (const char *)VAR_CRTSCTS},
227636285Sbrian  {"deflate", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
227736285Sbrian  "deflate window sizes", "set deflate out-winsize in-winsize",
227836285Sbrian  (const void *) VAR_WINSIZE},
227993418Sbrian#ifndef NODES
228067910Sbrian  {"mppe", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
228179370Sbrian  "MPPE key size and state", "set mppe [40|56|128|* [stateful|stateless|*]]",
228278411Sbrian  (const void *) VAR_MPPE},
228367910Sbrian#endif
228436285Sbrian  {"device", "line", SetVariable, LOCAL_AUTH | LOCAL_CX,
228546686Sbrian  "physical device name", "set device|line device-name[,device-name]",
228636285Sbrian  (const void *) VAR_DEVICE},
228736285Sbrian  {"dial", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
228836285Sbrian  "dialing script", "set dial chat-script", (const void *) VAR_DIAL},
228936285Sbrian  {"dns", NULL, SetVariable, LOCAL_AUTH, "Domain Name Server",
229036285Sbrian  "set dns pri-addr [sec-addr]", (const void *)VAR_DNS},
229136285Sbrian  {"enddisc", NULL, mp_SetEnddisc, LOCAL_AUTH,
229236285Sbrian  "Endpoint Discriminator", "set enddisc [IP|magic|label|psn value]"},
229336285Sbrian  {"escape", NULL, SetEscape, LOCAL_AUTH | LOCAL_CX,
229436285Sbrian  "escape characters", "set escape hex-digit ..."},
229536285Sbrian  {"filter", NULL, filter_Set, LOCAL_AUTH,
229636285Sbrian  "packet filters", "set filter alive|dial|in|out rule-no permit|deny "
229781634Sbrian  "[src_addr[/width]] [dst_addr[/width]] [proto "
229848142Sbrian  "[src [lt|eq|gt port]] [dst [lt|eq|gt port]] [estab] [syn] [finrst]]"},
229936285Sbrian  {"hangup", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
230036285Sbrian  "hangup script", "set hangup chat-script", (const void *) VAR_HANGUP},
230136285Sbrian  {"ifaddr", NULL, SetInterfaceAddr, LOCAL_AUTH, "destination address",
230231343Sbrian  "set ifaddr [src-addr [dst-addr [netmask [trg-addr]]]]"},
230361534Sbrian  {"ifqueue", NULL, SetVariable, LOCAL_AUTH, "interface queue",
230461534Sbrian  "set ifqueue packets", (const void *)VAR_IFQUEUE},
230544305Sbrian  {"ipcpretry", "ipcpretries", SetVariable, LOCAL_AUTH, "IPCP retries",
230644305Sbrian   "set ipcpretry value [attempts]", (const void *)VAR_IPCPRETRY},
230744305Sbrian  {"lcpretry", "lcpretries", SetVariable, LOCAL_AUTH | LOCAL_CX, "LCP retries",
230844305Sbrian   "set lcpretry value [attempts]", (const void *)VAR_LCPRETRY},
230936712Sbrian  {"log", NULL, log_SetLevel, LOCAL_AUTH, "log level",
231067916Sbrian  "set log [local] [+|-]all|async|cbcp|ccp|chat|command|connect|debug|dns|hdlc|"
231158033Sbrian  "id0|ipcp|lcp|lqm|phase|physical|sync|tcp/ip|timer|tun..."},
231236285Sbrian  {"login", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
231336285Sbrian  "login script", "set login chat-script", (const void *) VAR_LOGIN},
231452488Sbrian  {"logout", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
231552488Sbrian  "logout script", "set logout chat-script", (const void *) VAR_LOGOUT},
231636285Sbrian  {"lqrperiod", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
231736285Sbrian  "LQR period", "set lqrperiod value", (const void *)VAR_LQRPERIOD},
231836285Sbrian  {"mode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "mode value",
231936285Sbrian  "set mode interactive|auto|ddial|background", (const void *)VAR_MODE},
232036285Sbrian  {"mrru", NULL, SetVariable, LOCAL_AUTH, "MRRU value",
232136285Sbrian  "set mrru value", (const void *)VAR_MRRU},
232236285Sbrian  {"mru", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
232378410Sbrian  "MRU value", "set mru [max[imum]] [value]", (const void *)VAR_MRU},
232478410Sbrian  {"mtu", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
232578410Sbrian  "interface MTU value", "set mtu [max[imum]] [value]", (const void *)VAR_MTU},
232636285Sbrian  {"nbns", NULL, SetVariable, LOCAL_AUTH, "NetBIOS Name Server",
232736285Sbrian  "set nbns pri-addr [sec-addr]", (const void *)VAR_NBNS},
232836285Sbrian  {"openmode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "open mode",
232936285Sbrian  "set openmode active|passive [secs]", (const void *)VAR_OPENMODE},
233044305Sbrian  {"papretry", "papretries", SetVariable, LOCAL_AUTH | LOCAL_CX, "PAP retries",
233144305Sbrian   "set papretry value [attempts]", (const void *)VAR_PAPRETRY},
233246686Sbrian  {"parity", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "serial parity",
233346686Sbrian   "set parity [odd|even|none]", (const void *)VAR_PARITY},
233436285Sbrian  {"phone", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "telephone number(s)",
233536285Sbrian  "set phone phone1[:phone2[...]]", (const void *)VAR_PHONE},
233640679Sbrian  {"proctitle", "title", SetProcTitle, LOCAL_AUTH,
233740679Sbrian  "Process title", "set proctitle [value]"},
233843313Sbrian#ifndef NORADIUS
233943313Sbrian  {"radius", NULL, SetVariable, LOCAL_AUTH,
234043313Sbrian  "RADIUS Config", "set radius cfgfile", (const void *)VAR_RADIUS},
234143313Sbrian#endif
234236285Sbrian  {"reconnect", NULL, datalink_SetReconnect, LOCAL_AUTH | LOCAL_CX,
234336285Sbrian  "Reconnect timeout", "set reconnect value ntries"},
234440665Sbrian  {"recvpipe", NULL, SetVariable, LOCAL_AUTH,
234540665Sbrian  "RECVPIPE value", "set recvpipe value", (const void *)VAR_RECVPIPE},
234636285Sbrian  {"redial", NULL, datalink_SetRedial, LOCAL_AUTH | LOCAL_CX,
234744468Sbrian  "Redial timeout", "set redial secs[+inc[-incmax]][.next] [attempts]"},
234840665Sbrian  {"sendpipe", NULL, SetVariable, LOCAL_AUTH,
234940665Sbrian  "SENDPIPE value", "set sendpipe value", (const void *)VAR_SENDPIPE},
235071657Sbrian  {"server", "socket", SetServer, LOCAL_AUTH, "diagnostic port",
235171657Sbrian  "set server|socket TcpPort|LocalName|none|open|closed [password [mask]]"},
235236285Sbrian  {"speed", NULL, SetModemSpeed, LOCAL_AUTH | LOCAL_CX,
235346686Sbrian  "physical speed", "set speed value|sync"},
235436285Sbrian  {"stopped", NULL, SetStoppedTimeout, LOCAL_AUTH | LOCAL_CX,
235536285Sbrian  "STOPPED timeouts", "set stopped [LCPseconds [CCPseconds]]"},
235636285Sbrian  {"timeout", NULL, SetVariable, LOCAL_AUTH, "Idle timeout",
235736285Sbrian  "set timeout idletime", (const void *)VAR_IDLETIMEOUT},
235851048Sbrian  {"urgent", NULL, SetVariable, LOCAL_AUTH, "urgent ports",
235951048Sbrian  "set urgent [tcp|udp] [+|-]port...", (const void *)VAR_URGENTPORTS},
236036285Sbrian  {"vj", NULL, ipcp_vjset, LOCAL_AUTH,
236136285Sbrian  "vj values", "set vj slots|slotcomp [value]"},
236228679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
236331343Sbrian  "Display this message", "set help|? [command]", SetCommands},
236428679Sbrian  {NULL, NULL, NULL},
23656059Samurai};
23666059Samurai
23676059Samuraistatic int
236831343SbrianSetCommand(struct cmdargs const *arg)
23696059Samurai{
237036285Sbrian  if (arg->argc > arg->argn)
237136285Sbrian    FindExec(arg->bundle, SetCommands, arg->argc, arg->argn, arg->argv,
237236285Sbrian             arg->prompt, arg->cx);
237336285Sbrian  else if (arg->prompt)
237436285Sbrian    prompt_Printf(arg->prompt, "Use `set ?' to get a list or `set ? <var>' for"
237558044Sbrian	          " syntax help.\n");
23766059Samurai  else
237736285Sbrian    log_Printf(LogWARN, "set command must have arguments\n");
237826516Sbrian
237926516Sbrian  return 0;
23806059Samurai}
23816059Samurai
23826059Samuraistatic int
238331343SbrianAddCommand(struct cmdargs const *arg)
23846059Samurai{
238581634Sbrian  struct ncpaddr gw;
238681634Sbrian  struct ncprange dest;
238781634Sbrian  struct in_addr host;
238881634Sbrian  int dest_default, gw_arg, addrs;
23896059Samurai
239036285Sbrian  if (arg->argc != arg->argn+3 && arg->argc != arg->argn+2)
239131598Sbrian    return -1;
239231598Sbrian
239336285Sbrian  addrs = 0;
239481634Sbrian  dest_default = 0;
239581634Sbrian  if (arg->argc == arg->argn + 2) {
239636285Sbrian    if (!strcasecmp(arg->argv[arg->argn], "default"))
239781634Sbrian      dest_default = 1;
239831598Sbrian    else {
239981634Sbrian      if (!ncprange_aton(&dest, &arg->bundle->ncp, arg->argv[arg->argn]))
240036285Sbrian        return -1;
240136285Sbrian      if (!strncasecmp(arg->argv[arg->argn], "MYADDR", 6))
240236285Sbrian        addrs = ROUTE_DSTMYADDR;
240381634Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "MYADDR6", 7))
240481634Sbrian        addrs = ROUTE_DSTMYADDR6;
240536285Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "HISADDR", 7))
240636285Sbrian        addrs = ROUTE_DSTHISADDR;
240781634Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "HISADDR6", 8))
240881634Sbrian        addrs = ROUTE_DSTHISADDR6;
240958044Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "DNS0", 4))
241058044Sbrian        addrs = ROUTE_DSTDNS0;
241158044Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "DNS1", 4))
241258044Sbrian        addrs = ROUTE_DSTDNS1;
241331598Sbrian    }
241481634Sbrian    gw_arg = 1;
241534536Sbrian  } else {
241636285Sbrian    if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
241736285Sbrian      addrs = ROUTE_DSTMYADDR;
241881634Sbrian      host = arg->bundle->ncp.ipcp.my_ip;
241936285Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
242036285Sbrian      addrs = ROUTE_DSTHISADDR;
242181634Sbrian      host = arg->bundle->ncp.ipcp.peer_ip;
242258044Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "DNS0") == 0) {
242358044Sbrian      addrs = ROUTE_DSTDNS0;
242481634Sbrian      host = arg->bundle->ncp.ipcp.ns.dns[0];
242558044Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "DNS1") == 0) {
242658044Sbrian      addrs = ROUTE_DSTDNS1;
242781634Sbrian      host = arg->bundle->ncp.ipcp.ns.dns[1];
242865263Sbrian    } else {
242981634Sbrian      host = GetIpAddr(arg->argv[arg->argn]);
243081634Sbrian      if (host.s_addr == INADDR_NONE) {
243165263Sbrian        log_Printf(LogWARN, "%s: Invalid destination address\n",
243265263Sbrian                   arg->argv[arg->argn]);
243365263Sbrian        return -1;
243465263Sbrian      }
243565263Sbrian    }
243681634Sbrian    ncprange_setip4(&dest, host, GetIpAddr(arg->argv[arg->argn + 1]));
243781634Sbrian    gw_arg = 2;
24386059Samurai  }
243936285Sbrian
244081634Sbrian  if (strcasecmp(arg->argv[arg->argn + gw_arg], "HISADDR") == 0) {
244181634Sbrian    ncpaddr_setip4(&gw, arg->bundle->ncp.ipcp.peer_ip);
244236285Sbrian    addrs |= ROUTE_GWHISADDR;
244381634Sbrian#ifndef NOINET6
244481897Sbrian  } else if (strcasecmp(arg->argv[arg->argn + gw_arg], "HISADDR6") == 0) {
244581634Sbrian    ncpaddr_copy(&gw, &arg->bundle->ncp.ipv6cp.hisaddr);
244681634Sbrian    addrs |= ROUTE_GWHISADDR6;
244781634Sbrian#endif
244865263Sbrian  } else {
244981634Sbrian    if (!ncpaddr_aton(&gw, &arg->bundle->ncp, arg->argv[arg->argn + gw_arg])) {
245065263Sbrian      log_Printf(LogWARN, "%s: Invalid gateway address\n",
245181634Sbrian                 arg->argv[arg->argn + gw_arg]);
245265263Sbrian      return -1;
245365263Sbrian    }
245465263Sbrian  }
245536285Sbrian
245681634Sbrian  if (dest_default)
245781634Sbrian    ncprange_setdefault(&dest, ncpaddr_family(&gw));
245881634Sbrian
245981634Sbrian  if (rt_Set(arg->bundle, RTM_ADD, &dest, &gw, arg->cmd->args ? 1 : 0,
246081634Sbrian             ((addrs & ROUTE_GWHISADDR) || (addrs & ROUTE_GWHISADDR6)) ? 1 : 0)
246143313Sbrian      && addrs != ROUTE_STATIC)
246281634Sbrian    route_Add(&arg->bundle->ncp.route, addrs, &dest, &gw);
246336285Sbrian
246431598Sbrian  return 0;
24656059Samurai}
24666059Samurai
24676059Samuraistatic int
246831343SbrianDeleteCommand(struct cmdargs const *arg)
24696059Samurai{
247081634Sbrian  struct ncprange dest;
247136285Sbrian  int addrs;
24726059Samurai
247336285Sbrian  if (arg->argc == arg->argn+1) {
247436285Sbrian    if(strcasecmp(arg->argv[arg->argn], "all") == 0) {
247536285Sbrian      route_IfDelete(arg->bundle, 0);
247681634Sbrian      route_DeleteAll(&arg->bundle->ncp.route);
247736285Sbrian    } else {
247836285Sbrian      addrs = 0;
247936285Sbrian      if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
248081634Sbrian        ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.my_ip);
248136285Sbrian        addrs = ROUTE_DSTMYADDR;
248281634Sbrian#ifndef NOINET6
248381897Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "MYADDR6") == 0) {
248481634Sbrian        ncprange_sethost(&dest, &arg->bundle->ncp.ipv6cp.myaddr);
248581634Sbrian        addrs = ROUTE_DSTMYADDR6;
248681634Sbrian#endif
248736285Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
248881634Sbrian        ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.peer_ip);
248936285Sbrian        addrs = ROUTE_DSTHISADDR;
249081634Sbrian#ifndef NOINET6
249181897Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "HISADDR6") == 0) {
249281634Sbrian        ncprange_sethost(&dest, &arg->bundle->ncp.ipv6cp.hisaddr);
249381634Sbrian        addrs = ROUTE_DSTHISADDR6;
249481634Sbrian#endif
249558044Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "DNS0") == 0) {
249681634Sbrian        ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.ns.dns[0]);
249758044Sbrian        addrs = ROUTE_DSTDNS0;
249858044Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "DNS1") == 0) {
249981634Sbrian        ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.ns.dns[1]);
250058044Sbrian        addrs = ROUTE_DSTDNS1;
250136285Sbrian      } else {
250281634Sbrian        ncprange_aton(&dest, &arg->bundle->ncp, arg->argv[arg->argn]);
250336285Sbrian        addrs = ROUTE_STATIC;
250436285Sbrian      }
250581634Sbrian      rt_Set(arg->bundle, RTM_DELETE, &dest, NULL, arg->cmd->args ? 1 : 0, 0);
250681634Sbrian      route_Delete(&arg->bundle->ncp.route, addrs, &dest);
250731598Sbrian    }
250834536Sbrian  } else
250926516Sbrian    return -1;
251026516Sbrian
251126516Sbrian  return 0;
25126059Samurai}
25136059Samurai
251450059Sbrian#ifndef NONAT
251526031Sbrianstatic int
251658867SbrianNatEnable(struct cmdargs const *arg)
251726031Sbrian{
251836285Sbrian  if (arg->argc == arg->argn+1) {
251936285Sbrian    if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
252050059Sbrian      if (!arg->bundle->NatEnabled) {
252146686Sbrian        if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED)
252246686Sbrian          PacketAliasSetAddress(arg->bundle->ncp.ipcp.my_ip);
252350059Sbrian        arg->bundle->NatEnabled = 1;
252446686Sbrian      }
252537191Sbrian      return 0;
252636285Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "no") == 0) {
252750059Sbrian      arg->bundle->NatEnabled = 0;
252840561Sbrian      arg->bundle->cfg.opt &= ~OPT_IFACEALIAS;
252940561Sbrian      /* Don't iface_Clear() - there may be manually configured addresses */
253026516Sbrian      return 0;
253126142Sbrian    }
253235449Sbrian  }
253336285Sbrian
253426516Sbrian  return -1;
253526031Sbrian}
253626031Sbrian
253726031Sbrian
253826031Sbrianstatic int
253958867SbrianNatOption(struct cmdargs const *arg)
254026031Sbrian{
254138559Sbrian  long param = (long)arg->cmd->args;
254238559Sbrian
254336285Sbrian  if (arg->argc == arg->argn+1) {
254436285Sbrian    if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
254550059Sbrian      if (arg->bundle->NatEnabled) {
254637191Sbrian	PacketAliasSetMode(param, param);
254728679Sbrian	return 0;
254828679Sbrian      }
254950059Sbrian      log_Printf(LogWARN, "nat not enabled\n");
255036285Sbrian    } else if (strcmp(arg->argv[arg->argn], "no") == 0) {
255150059Sbrian      if (arg->bundle->NatEnabled) {
255237191Sbrian	PacketAliasSetMode(0, param);
255328679Sbrian	return 0;
255428679Sbrian      }
255550059Sbrian      log_Printf(LogWARN, "nat not enabled\n");
255628679Sbrian    }
255735449Sbrian  }
255828679Sbrian  return -1;
255926031Sbrian}
256050059Sbrian#endif /* #ifndef NONAT */
256131121Sbrian
256231121Sbrianstatic int
256336285SbrianLinkCommand(struct cmdargs const *arg)
256436285Sbrian{
256536285Sbrian  if (arg->argc > arg->argn+1) {
256636285Sbrian    char namelist[LINE_LEN];
256736285Sbrian    struct datalink *cx;
256836285Sbrian    char *name;
256936285Sbrian    int result = 0;
257036285Sbrian
257136285Sbrian    if (!strcmp(arg->argv[arg->argn], "*")) {
257236285Sbrian      struct datalink *dl;
257336285Sbrian
257436285Sbrian      cx = arg->bundle->links;
257536285Sbrian      while (cx) {
257636285Sbrian        /* Watch it, the command could be a ``remove'' */
257736285Sbrian        dl = cx->next;
257836285Sbrian        FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
257936285Sbrian                 arg->prompt, cx);
258036285Sbrian        for (cx = arg->bundle->links; cx; cx = cx->next)
258136285Sbrian          if (cx == dl)
258236285Sbrian            break;		/* Pointer's still valid ! */
258336285Sbrian      }
258436285Sbrian    } else {
258536285Sbrian      strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
258636285Sbrian      namelist[sizeof namelist - 1] = '\0';
258736285Sbrian      for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
258836285Sbrian        if (!bundle2datalink(arg->bundle, name)) {
258936285Sbrian          log_Printf(LogWARN, "link: %s: Invalid link name\n", name);
259036285Sbrian          return 1;
259136285Sbrian        }
259236285Sbrian
259336285Sbrian      strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
259436285Sbrian      namelist[sizeof namelist - 1] = '\0';
259536285Sbrian      for(name = strtok(namelist, ", "); name; name = strtok(NULL,", ")) {
259636285Sbrian        cx = bundle2datalink(arg->bundle, name);
259736285Sbrian        if (cx)
259836285Sbrian          FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
259936285Sbrian                   arg->prompt, cx);
260036285Sbrian        else {
260136285Sbrian          log_Printf(LogWARN, "link: %s: Invalidated link name !\n", name);
260236285Sbrian          result++;
260336285Sbrian        }
260436285Sbrian      }
260536285Sbrian    }
260636285Sbrian    return result;
260736285Sbrian  }
260836285Sbrian
260995258Sdes  log_Printf(LogWARN, "usage: %s\n", arg->cmd->syntax);
261036285Sbrian  return 2;
261136285Sbrian}
261236285Sbrian
261336285Sbrianstruct link *
261436285Sbriancommand_ChooseLink(struct cmdargs const *arg)
261536285Sbrian{
261636285Sbrian  if (arg->cx)
261736285Sbrian    return &arg->cx->physical->link;
261837210Sbrian  else if (!arg->bundle->ncp.mp.cfg.mrru) {
261936285Sbrian    struct datalink *dl = bundle2datalink(arg->bundle, NULL);
262037210Sbrian    if (dl)
262137210Sbrian      return &dl->physical->link;
262236285Sbrian  }
262337210Sbrian  return &arg->bundle->ncp.mp.link;
262436285Sbrian}
262536285Sbrian
262636285Sbrianstatic const char *
262736285Sbrianident_cmd(const char *cmd, unsigned *keep, unsigned *add)
262836285Sbrian{
262936285Sbrian  const char *result;
263036285Sbrian
263136285Sbrian  switch (*cmd) {
263236285Sbrian    case 'A':
263336285Sbrian    case 'a':
263436285Sbrian      result = "accept";
263536285Sbrian      *keep = NEG_MYMASK;
263636285Sbrian      *add = NEG_ACCEPTED;
263736285Sbrian      break;
263836285Sbrian    case 'D':
263936285Sbrian    case 'd':
264036285Sbrian      switch (cmd[1]) {
264136285Sbrian        case 'E':
264236285Sbrian        case 'e':
264336285Sbrian          result = "deny";
264436285Sbrian          *keep = NEG_MYMASK;
264536285Sbrian          *add = 0;
264636285Sbrian          break;
264736285Sbrian        case 'I':
264836285Sbrian        case 'i':
264936285Sbrian          result = "disable";
265036285Sbrian          *keep = NEG_HISMASK;
265136285Sbrian          *add = 0;
265236285Sbrian          break;
265336285Sbrian        default:
265436285Sbrian          return NULL;
265536285Sbrian      }
265636285Sbrian      break;
265736285Sbrian    case 'E':
265836285Sbrian    case 'e':
265936285Sbrian      result = "enable";
266036285Sbrian      *keep = NEG_HISMASK;
266136285Sbrian      *add = NEG_ENABLED;
266236285Sbrian      break;
266336285Sbrian    default:
266436285Sbrian      return NULL;
266536285Sbrian  }
266636285Sbrian
266736285Sbrian  return result;
266836285Sbrian}
266936285Sbrian
267036285Sbrianstatic int
267136285SbrianOptSet(struct cmdargs const *arg)
267236285Sbrian{
267337574Sbrian  int bit = (int)(long)arg->cmd->args;
267436285Sbrian  unsigned keep;			/* Keep these bits */
267536285Sbrian  unsigned add;				/* Add these bits */
267636285Sbrian
267781697Sbrian  if (ident_cmd(arg->argv[arg->argn - 2], &keep, &add) == NULL)
267836285Sbrian    return 1;
267936285Sbrian
268081885Sbrian#ifndef NOINET6
268181697Sbrian  if (add == NEG_ENABLED && bit == OPT_IPV6CP && !probe.ipv6_available) {
268281697Sbrian    log_Printf(LogWARN, "IPv6 is not available on this machine\n");
268381697Sbrian    return 1;
268481697Sbrian  }
268581885Sbrian#endif
268681697Sbrian
268736285Sbrian  if (add)
268836285Sbrian    arg->bundle->cfg.opt |= bit;
268936285Sbrian  else
269036285Sbrian    arg->bundle->cfg.opt &= ~bit;
269181697Sbrian
269236285Sbrian  return 0;
269336285Sbrian}
269436285Sbrian
269536285Sbrianstatic int
269640561SbrianIfaceAliasOptSet(struct cmdargs const *arg)
269740561Sbrian{
269840561Sbrian  unsigned save = arg->bundle->cfg.opt;
269940561Sbrian  int result = OptSet(arg);
270040561Sbrian
270140561Sbrian  if (result == 0)
270250059Sbrian    if (Enabled(arg->bundle, OPT_IFACEALIAS) && !arg->bundle->NatEnabled) {
270340561Sbrian      arg->bundle->cfg.opt = save;
270450059Sbrian      log_Printf(LogWARN, "Cannot enable iface-alias without NAT\n");
270540561Sbrian      result = 2;
270640561Sbrian    }
270740561Sbrian
270840561Sbrian  return result;
270940561Sbrian}
271040561Sbrian
271140561Sbrianstatic int
271236285SbrianNegotiateSet(struct cmdargs const *arg)
271336285Sbrian{
271437210Sbrian  long param = (long)arg->cmd->args;
271536285Sbrian  struct link *l = command_ChooseLink(arg);	/* LOCAL_CX_OPT uses this */
271636285Sbrian  struct datalink *cx = arg->cx;	/* LOCAL_CX uses this */
271736285Sbrian  const char *cmd;
271836285Sbrian  unsigned keep;			/* Keep these bits */
271936285Sbrian  unsigned add;				/* Add these bits */
272036285Sbrian
272136285Sbrian  if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL)
272236285Sbrian    return 1;
272336285Sbrian
272436285Sbrian  if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
272536285Sbrian    log_Printf(LogWARN, "%s %s: No context (use the `link' command)\n",
272636285Sbrian              cmd, arg->cmd->name);
272736285Sbrian    return 2;
272836285Sbrian  } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
272936285Sbrian    log_Printf(LogWARN, "%s %s: Redundant context (%s) ignored\n",
273036285Sbrian              cmd, arg->cmd->name, cx->name);
273136285Sbrian    cx = NULL;
273236285Sbrian  }
273336285Sbrian
273436285Sbrian  switch (param) {
273536285Sbrian    case NEG_ACFCOMP:
273636285Sbrian      cx->physical->link.lcp.cfg.acfcomp &= keep;
273736285Sbrian      cx->physical->link.lcp.cfg.acfcomp |= add;
273836285Sbrian      break;
273944106Sbrian    case NEG_CHAP05:
274044106Sbrian      cx->physical->link.lcp.cfg.chap05 &= keep;
274144106Sbrian      cx->physical->link.lcp.cfg.chap05 |= add;
274236285Sbrian      break;
274393418Sbrian#ifndef NODES
274444106Sbrian    case NEG_CHAP80:
274544106Sbrian      cx->physical->link.lcp.cfg.chap80nt &= keep;
274644106Sbrian      cx->physical->link.lcp.cfg.chap80nt |= add;
274744106Sbrian      break;
274844106Sbrian    case NEG_CHAP80LM:
274944106Sbrian      cx->physical->link.lcp.cfg.chap80lm &= keep;
275044106Sbrian      cx->physical->link.lcp.cfg.chap80lm |= add;
275144106Sbrian      break;
275267910Sbrian    case NEG_CHAP81:
275367910Sbrian      cx->physical->link.lcp.cfg.chap81 &= keep;
275467910Sbrian      cx->physical->link.lcp.cfg.chap81 |= add;
275567910Sbrian      break;
275667910Sbrian    case NEG_MPPE:
275767910Sbrian      l->ccp.cfg.neg[CCP_NEG_MPPE] &= keep;
275867910Sbrian      l->ccp.cfg.neg[CCP_NEG_MPPE] |= add;
275967910Sbrian      break;
276044106Sbrian#endif
276136285Sbrian    case NEG_DEFLATE:
276236285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE] &= keep;
276336285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE] |= add;
276436285Sbrian      break;
276536285Sbrian    case NEG_DNS:
276636285Sbrian      arg->bundle->ncp.ipcp.cfg.ns.dns_neg &= keep;
276736285Sbrian      arg->bundle->ncp.ipcp.cfg.ns.dns_neg |= add;
276836285Sbrian      break;
276947858Sbrian    case NEG_ENDDISC:
277047858Sbrian      arg->bundle->ncp.mp.cfg.negenddisc &= keep;
277147858Sbrian      arg->bundle->ncp.mp.cfg.negenddisc |= add;
277247858Sbrian      break;
277336285Sbrian    case NEG_LQR:
277436285Sbrian      cx->physical->link.lcp.cfg.lqr &= keep;
277536285Sbrian      cx->physical->link.lcp.cfg.lqr |= add;
277636285Sbrian      break;
277736285Sbrian    case NEG_PAP:
277836285Sbrian      cx->physical->link.lcp.cfg.pap &= keep;
277936285Sbrian      cx->physical->link.lcp.cfg.pap |= add;
278036285Sbrian      break;
278136285Sbrian    case NEG_PPPDDEFLATE:
278236285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE24] &= keep;
278336285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE24] |= add;
278436285Sbrian      break;
278536285Sbrian    case NEG_PRED1:
278636285Sbrian      l->ccp.cfg.neg[CCP_NEG_PRED1] &= keep;
278736285Sbrian      l->ccp.cfg.neg[CCP_NEG_PRED1] |= add;
278836285Sbrian      break;
278936285Sbrian    case NEG_PROTOCOMP:
279036285Sbrian      cx->physical->link.lcp.cfg.protocomp &= keep;
279136285Sbrian      cx->physical->link.lcp.cfg.protocomp |= add;
279236285Sbrian      break;
279336285Sbrian    case NEG_SHORTSEQ:
279440622Sbrian      switch (bundle_Phase(arg->bundle)) {
279540622Sbrian        case PHASE_DEAD:
279640622Sbrian          break;
279740622Sbrian        case PHASE_ESTABLISH:
279840622Sbrian          /* Make sure none of our links are DATALINK_LCP or greater */
279940622Sbrian          if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) {
280040622Sbrian            log_Printf(LogWARN, "shortseq: Only changable before"
280140622Sbrian                       " LCP negotiations\n");
280240622Sbrian            return 1;
280340622Sbrian          }
280440622Sbrian          break;
280540622Sbrian        default:
280640622Sbrian          log_Printf(LogWARN, "shortseq: Only changable at phase"
280740622Sbrian                     " DEAD/ESTABLISH\n");
280840622Sbrian          return 1;
280936285Sbrian      }
281040622Sbrian      arg->bundle->ncp.mp.cfg.shortseq &= keep;
281140622Sbrian      arg->bundle->ncp.mp.cfg.shortseq |= add;
281236285Sbrian      break;
281336285Sbrian    case NEG_VJCOMP:
281436285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.neg &= keep;
281536285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.neg |= add;
281636285Sbrian      break;
281736285Sbrian  }
281836285Sbrian
281936285Sbrian  return 0;
282036285Sbrian}
282136285Sbrian
282236285Sbrianstatic struct cmdtab const NegotiateCommands[] = {
282362778Sbrian  {"filter-decapsulation", NULL, OptSet, LOCAL_AUTH,
282462778Sbrian  "filter on PPPoUDP payloads", "disable|enable",
282562778Sbrian  (const void *)OPT_FILTERDECAP},
282636285Sbrian  {"idcheck", NULL, OptSet, LOCAL_AUTH, "Check FSM reply ids",
282736285Sbrian  "disable|enable", (const void *)OPT_IDCHECK},
282840666Sbrian  {"iface-alias", NULL, IfaceAliasOptSet, LOCAL_AUTH,
282962778Sbrian  "retain interface addresses", "disable|enable",
283062778Sbrian  (const void *)OPT_IFACEALIAS},
283181634Sbrian#ifndef NOINET6
283281634Sbrian  {"ipcp", NULL, OptSet, LOCAL_AUTH, "IP Network Control Protocol",
283381634Sbrian  "disable|enable", (const void *)OPT_IPCP},
283481634Sbrian  {"ipv6cp", NULL, OptSet, LOCAL_AUTH, "IPv6 Network Control Protocol",
283581634Sbrian  "disable|enable", (const void *)OPT_IPV6CP},
283681634Sbrian#endif
283747689Sbrian  {"keep-session", NULL, OptSet, LOCAL_AUTH, "Retain device session leader",
283847689Sbrian  "disable|enable", (const void *)OPT_KEEPSESSION},
283936285Sbrian  {"loopback", NULL, OptSet, LOCAL_AUTH, "Loop packets for local iface",
284036285Sbrian  "disable|enable", (const void *)OPT_LOOPBACK},
284136285Sbrian  {"passwdauth", NULL, OptSet, LOCAL_AUTH, "Use passwd file",
284236285Sbrian  "disable|enable", (const void *)OPT_PASSWDAUTH},
284340665Sbrian  {"proxy", NULL, OptSet, LOCAL_AUTH, "Create a proxy ARP entry",
284436285Sbrian  "disable|enable", (const void *)OPT_PROXY},
284540665Sbrian  {"proxyall", NULL, OptSet, LOCAL_AUTH, "Proxy ARP for all remote hosts",
284640665Sbrian  "disable|enable", (const void *)OPT_PROXYALL},
284736285Sbrian  {"sroutes", NULL, OptSet, LOCAL_AUTH, "Use sticky routes",
284836285Sbrian  "disable|enable", (const void *)OPT_SROUTES},
284969303Sbrian  {"tcpmssfixup", "mssfixup", OptSet, LOCAL_AUTH, "Modify MSS options",
285069303Sbrian  "disable|enable", (const void *)OPT_TCPMSSFIXUP},
285136285Sbrian  {"throughput", NULL, OptSet, LOCAL_AUTH, "Rolling throughput",
285236285Sbrian  "disable|enable", (const void *)OPT_THROUGHPUT},
285336285Sbrian  {"utmp", NULL, OptSet, LOCAL_AUTH, "Log connections in utmp",
285436285Sbrian  "disable|enable", (const void *)OPT_UTMP},
285536285Sbrian
285681634Sbrian#ifndef NOINET6
285781634Sbrian#define OPT_MAX 13	/* accept/deny allowed below and not above */
285881634Sbrian#else
285981634Sbrian#define OPT_MAX 11
286081634Sbrian#endif
286136285Sbrian
286236285Sbrian  {"acfcomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
286336285Sbrian  "Address & Control field compression", "accept|deny|disable|enable",
286436285Sbrian  (const void *)NEG_ACFCOMP},
286544106Sbrian  {"chap", "chap05", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
286636285Sbrian  "Challenge Handshake Authentication Protocol", "accept|deny|disable|enable",
286744106Sbrian  (const void *)NEG_CHAP05},
286893418Sbrian#ifndef NODES
286944106Sbrian  {"mschap", "chap80nt", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
287044106Sbrian  "Microsoft (NT) CHAP", "accept|deny|disable|enable",
287144106Sbrian  (const void *)NEG_CHAP80},
287244106Sbrian  {"LANMan", "chap80lm", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
287344106Sbrian  "Microsoft (NT) CHAP", "accept|deny|disable|enable",
287444106Sbrian  (const void *)NEG_CHAP80LM},
287567910Sbrian  {"mschapv2", "chap81", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
287667910Sbrian  "Microsoft CHAP v2", "accept|deny|disable|enable",
287767910Sbrian  (const void *)NEG_CHAP81},
287867910Sbrian  {"mppe", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
287967910Sbrian  "MPPE encryption", "accept|deny|disable|enable",
288067910Sbrian  (const void *)NEG_MPPE},
288144106Sbrian#endif
288236285Sbrian  {"deflate", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
288336285Sbrian  "Deflate compression", "accept|deny|disable|enable",
288436285Sbrian  (const void *)NEG_DEFLATE},
288536285Sbrian  {"deflate24", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
288636285Sbrian  "Deflate (type 24) compression", "accept|deny|disable|enable",
288736285Sbrian  (const void *)NEG_PPPDDEFLATE},
288836285Sbrian  {"dns", NULL, NegotiateSet, LOCAL_AUTH,
288936285Sbrian  "DNS specification", "accept|deny|disable|enable", (const void *)NEG_DNS},
289047858Sbrian  {"enddisc", NULL, NegotiateSet, LOCAL_AUTH, "ENDDISC negotiation",
289147858Sbrian  "accept|deny|disable|enable", (const void *)NEG_ENDDISC},
289236285Sbrian  {"lqr", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
289336285Sbrian  "Link Quality Reports", "accept|deny|disable|enable",
289436285Sbrian  (const void *)NEG_LQR},
289536285Sbrian  {"pap", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
289636285Sbrian  "Password Authentication protocol", "accept|deny|disable|enable",
289736285Sbrian  (const void *)NEG_PAP},
289836285Sbrian  {"pred1", "predictor1", NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
289936285Sbrian  "Predictor 1 compression", "accept|deny|disable|enable",
290036285Sbrian  (const void *)NEG_PRED1},
290136285Sbrian  {"protocomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
290236285Sbrian  "Protocol field compression", "accept|deny|disable|enable",
290336285Sbrian  (const void *)NEG_PROTOCOMP},
290436285Sbrian  {"shortseq", NULL, NegotiateSet, LOCAL_AUTH,
290536285Sbrian  "MP Short Sequence Numbers", "accept|deny|disable|enable",
290636285Sbrian  (const void *)NEG_SHORTSEQ},
290736285Sbrian  {"vjcomp", NULL, NegotiateSet, LOCAL_AUTH,
290836285Sbrian  "Van Jacobson header compression", "accept|deny|disable|enable",
290936285Sbrian  (const void *)NEG_VJCOMP},
291036285Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
291136285Sbrian  "Display this message", "accept|deny|disable|enable help|? [value]",
291236285Sbrian  NegotiateCommands},
291336285Sbrian  {NULL, NULL, NULL},
291436285Sbrian};
291536285Sbrian
291636285Sbrianstatic int
291736285SbrianNegotiateCommand(struct cmdargs const *arg)
291836285Sbrian{
291936285Sbrian  if (arg->argc > arg->argn) {
292036285Sbrian    char const *argv[3];
292136285Sbrian    unsigned keep, add;
292236285Sbrian    int n;
292336285Sbrian
292436285Sbrian    if ((argv[0] = ident_cmd(arg->argv[arg->argn-1], &keep, &add)) == NULL)
292536285Sbrian      return -1;
292636285Sbrian    argv[2] = NULL;
292736285Sbrian
292836285Sbrian    for (n = arg->argn; n < arg->argc; n++) {
292936285Sbrian      argv[1] = arg->argv[n];
293036285Sbrian      FindExec(arg->bundle, NegotiateCommands + (keep == NEG_HISMASK ?
293136285Sbrian               0 : OPT_MAX), 2, 1, argv, arg->prompt, arg->cx);
293236285Sbrian    }
293336285Sbrian  } else if (arg->prompt)
293436285Sbrian    prompt_Printf(arg->prompt, "Use `%s ?' to get a list.\n",
293536285Sbrian	    arg->argv[arg->argn-1]);
293636285Sbrian  else
293736285Sbrian    log_Printf(LogWARN, "%s command must have arguments\n",
293836285Sbrian              arg->argv[arg->argn] );
293936285Sbrian
294036285Sbrian  return 0;
294136285Sbrian}
294236285Sbrian
294336285Sbrianconst char *
294436285Sbriancommand_ShowNegval(unsigned val)
294536285Sbrian{
294636285Sbrian  switch (val&3) {
294736285Sbrian    case 1: return "disabled & accepted";
294836285Sbrian    case 2: return "enabled & denied";
294936285Sbrian    case 3: return "enabled & accepted";
295036285Sbrian  }
295136285Sbrian  return "disabled & denied";
295236285Sbrian}
295336934Sbrian
295436934Sbrianstatic int
295536934SbrianClearCommand(struct cmdargs const *arg)
295636934Sbrian{
295736934Sbrian  struct pppThroughput *t;
295836934Sbrian  struct datalink *cx;
295936934Sbrian  int i, clear_type;
296036934Sbrian
296136934Sbrian  if (arg->argc < arg->argn + 1)
296236934Sbrian    return -1;
296336934Sbrian
296446686Sbrian  if (strcasecmp(arg->argv[arg->argn], "physical") == 0) {
296536934Sbrian    cx = arg->cx;
296636934Sbrian    if (!cx)
296736934Sbrian      cx = bundle2datalink(arg->bundle, NULL);
296836934Sbrian    if (!cx) {
296946686Sbrian      log_Printf(LogWARN, "A link must be specified for ``clear physical''\n");
297036934Sbrian      return 1;
297136934Sbrian    }
297264652Sbrian    t = &cx->physical->link.stats.total;
297336934Sbrian  } else if (strcasecmp(arg->argv[arg->argn], "ipcp") == 0)
297436934Sbrian    t = &arg->bundle->ncp.ipcp.throughput;
297581634Sbrian#ifndef NOINET6
297681897Sbrian  else if (strcasecmp(arg->argv[arg->argn], "ipv6cp") == 0)
297781634Sbrian    t = &arg->bundle->ncp.ipv6cp.throughput;
297881634Sbrian#endif
297936934Sbrian  else
298036934Sbrian    return -1;
298136934Sbrian
298236934Sbrian  if (arg->argc > arg->argn + 1) {
298336934Sbrian    clear_type = 0;
298436934Sbrian    for (i = arg->argn + 1; i < arg->argc; i++)
298536934Sbrian      if (strcasecmp(arg->argv[i], "overall") == 0)
298636934Sbrian        clear_type |= THROUGHPUT_OVERALL;
298736934Sbrian      else if (strcasecmp(arg->argv[i], "current") == 0)
298836934Sbrian        clear_type |= THROUGHPUT_CURRENT;
298936934Sbrian      else if (strcasecmp(arg->argv[i], "peak") == 0)
299036934Sbrian        clear_type |= THROUGHPUT_PEAK;
299136934Sbrian      else
299236934Sbrian        return -1;
299336934Sbrian  } else
299436934Sbrian    clear_type = THROUGHPUT_ALL;
299536934Sbrian
299636934Sbrian  throughput_clear(t, clear_type, arg->prompt);
299736934Sbrian  return 0;
299836934Sbrian}
299940561Sbrian
300040561Sbrianstatic int
300140561SbrianRunListCommand(struct cmdargs const *arg)
300240561Sbrian{
300340561Sbrian  const char *cmd = arg->argc ? arg->argv[arg->argc - 1] : "???";
300440561Sbrian
300564801Sbrian#ifndef NONAT
300664801Sbrian  if (arg->cmd->args == NatCommands &&
300764801Sbrian      tolower(*arg->argv[arg->argn - 1]) == 'a') {
300864801Sbrian    if (arg->prompt)
300965550Sbrian      prompt_Printf(arg->prompt, "The alias command is deprecated\n");
301064801Sbrian    else
301165550Sbrian      log_Printf(LogWARN, "The alias command is deprecated\n");
301264801Sbrian  }
301364801Sbrian#endif
301464801Sbrian
301540561Sbrian  if (arg->argc > arg->argn)
301640561Sbrian    FindExec(arg->bundle, arg->cmd->args, arg->argc, arg->argn, arg->argv,
301740561Sbrian             arg->prompt, arg->cx);
301840561Sbrian  else if (arg->prompt)
301940561Sbrian    prompt_Printf(arg->prompt, "Use `%s help' to get a list or `%s help"
302040561Sbrian                  " <option>' for syntax help.\n", cmd, cmd);
302140561Sbrian  else
302240561Sbrian    log_Printf(LogWARN, "%s command must have arguments\n", cmd);
302340561Sbrian
302440561Sbrian  return 0;
302540561Sbrian}
302640561Sbrian
302740561Sbrianstatic int
302840561SbrianIfaceAddCommand(struct cmdargs const *arg)
302940561Sbrian{
303081634Sbrian  struct ncpaddr peer, addr;
303181634Sbrian  struct ncprange ifa;
303281634Sbrian  struct in_addr mask;
303381634Sbrian  int n, how;
303440561Sbrian
303540664Sbrian  if (arg->argc == arg->argn + 1) {
303681634Sbrian    if (!ncprange_aton(&ifa, NULL, arg->argv[arg->argn]))
303740561Sbrian      return -1;
303881634Sbrian    ncpaddr_init(&peer);
303940664Sbrian  } else {
304040664Sbrian    if (arg->argc == arg->argn + 2) {
304181634Sbrian      if (!ncprange_aton(&ifa, NULL, arg->argv[arg->argn]))
304240664Sbrian        return -1;
304340664Sbrian      n = 1;
304440664Sbrian    } else if (arg->argc == arg->argn + 3) {
304581634Sbrian      if (!ncpaddr_aton(&addr, NULL, arg->argv[arg->argn]))
304640664Sbrian        return -1;
304781634Sbrian      if (ncpaddr_family(&addr) != AF_INET)
304840664Sbrian        return -1;
304981634Sbrian      ncprange_sethost(&ifa, &addr);
305081634Sbrian      if (!ncpaddr_aton(&addr, NULL, arg->argv[arg->argn + 1]))
305181634Sbrian        return -1;
305281634Sbrian      if (!ncpaddr_getip4(&addr, &mask))
305381634Sbrian        return -1;
305481634Sbrian      if (!ncprange_setip4mask(&ifa, mask))
305581634Sbrian        return -1;
305640664Sbrian      n = 2;
305740664Sbrian    } else
305840561Sbrian      return -1;
305940561Sbrian
306081634Sbrian    if (!ncpaddr_aton(&peer, NULL, arg->argv[arg->argn + n]))
306140664Sbrian      return -1;
306281634Sbrian
306381634Sbrian    if (ncprange_family(&ifa) != ncpaddr_family(&peer)) {
306481634Sbrian      log_Printf(LogWARN, "IfaceAddCommand: src and dst address families"
306581634Sbrian                 " differ\n");
306681634Sbrian      return -1;
306781634Sbrian    }
306840664Sbrian  }
306940561Sbrian
307040561Sbrian  how = IFACE_ADD_LAST;
307140561Sbrian  if (arg->cmd->args)
307240561Sbrian    how |= IFACE_FORCE_ADD;
307340561Sbrian
307481634Sbrian  return !iface_Add(arg->bundle->iface, &arg->bundle->ncp, &ifa, &peer, how);
307540561Sbrian}
307640561Sbrian
307740561Sbrianstatic int
307840561SbrianIfaceDeleteCommand(struct cmdargs const *arg)
307940561Sbrian{
308081634Sbrian  struct ncpaddr ifa;
308181634Sbrian  struct in_addr ifa4;
308240561Sbrian  int ok;
308340561Sbrian
308440561Sbrian  if (arg->argc != arg->argn + 1)
308540561Sbrian    return -1;
308640561Sbrian
308781634Sbrian  if (!ncpaddr_aton(&ifa, NULL, arg->argv[arg->argn]))
308840561Sbrian    return -1;
308940561Sbrian
309040561Sbrian  if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED &&
309181634Sbrian      ncpaddr_getip4(&ifa, &ifa4) &&
309281634Sbrian      arg->bundle->ncp.ipcp.my_ip.s_addr == ifa4.s_addr) {
309340561Sbrian    log_Printf(LogWARN, "%s: Cannot remove active interface address\n",
309481634Sbrian               ncpaddr_ntoa(&ifa));
309540561Sbrian    return 1;
309640561Sbrian  }
309740561Sbrian
309881634Sbrian  ok = iface_Delete(arg->bundle->iface, &arg->bundle->ncp, &ifa);
309940561Sbrian  if (!ok) {
310040561Sbrian    if (arg->cmd->args)
310140561Sbrian      ok = 1;
310240561Sbrian    else if (arg->prompt)
310381634Sbrian      prompt_Printf(arg->prompt, "%s: No such interface address\n",
310481634Sbrian                    ncpaddr_ntoa(&ifa));
310540561Sbrian    else
310681634Sbrian      log_Printf(LogWARN, "%s: No such interface address\n",
310781634Sbrian                 ncpaddr_ntoa(&ifa));
310840561Sbrian  }
310940561Sbrian
311040561Sbrian  return !ok;
311140561Sbrian}
311240561Sbrian
311340561Sbrianstatic int
311440561SbrianIfaceClearCommand(struct cmdargs const *arg)
311540561Sbrian{
311681634Sbrian  int family, how;
311740561Sbrian
311881634Sbrian  family = 0;
311981634Sbrian  if (arg->argc == arg->argn + 1) {
312081634Sbrian    if (strcasecmp(arg->argv[arg->argn], "inet") == 0)
312181634Sbrian      family = AF_INET;
312281634Sbrian#ifndef NOINET6
312381897Sbrian    else if (strcasecmp(arg->argv[arg->argn], "inet6") == 0)
312481634Sbrian      family = AF_INET6;
312581634Sbrian#endif
312681634Sbrian    else
312781634Sbrian      return -1;
312881634Sbrian  } else if (arg->argc != arg->argn)
312940561Sbrian    return -1;
313040561Sbrian
313140941Sbrian  how = arg->bundle->ncp.ipcp.fsm.state == ST_OPENED ||
313240941Sbrian        arg->bundle->phys_type.all & PHYS_AUTO ?
313340561Sbrian        IFACE_CLEAR_ALIASES : IFACE_CLEAR_ALL;
313481634Sbrian  iface_Clear(arg->bundle->iface, &arg->bundle->ncp, family, how);
313540561Sbrian
313640561Sbrian  return 0;
313740561Sbrian}
313840679Sbrian
313940679Sbrianstatic int
314040679SbrianSetProcTitle(struct cmdargs const *arg)
314140679Sbrian{
314240679Sbrian  static char title[LINE_LEN];
314386028Sbrian  char *argv[MAXARGS];
314486028Sbrian  int argc = arg->argc - arg->argn;
314540679Sbrian
314640679Sbrian  if (arg->argc == arg->argn) {
314764698Sbrian    SetTitle(NULL);
314840679Sbrian    return 0;
314940679Sbrian  }
315040679Sbrian
315140679Sbrian  if (argc >= sizeof argv / sizeof argv[0]) {
315240679Sbrian    argc = sizeof argv / sizeof argv[0] - 1;
315340679Sbrian    log_Printf(LogWARN, "Truncating proc title to %d args\n", argc);
315440679Sbrian  }
315547849Sbrian  command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 1, getpid());
315685991Sbrian  Concatinate(title, sizeof title, argc, (const char *const *)argv);
315764698Sbrian  SetTitle(title);
315885991Sbrian  command_Free(argc, argv);
315940679Sbrian
316040679Sbrian  return 0;
316140679Sbrian}
3162