command.c revision 81697
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 81697 2001-08-15 13:53:38Z brian $
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
16781634Sbrianconst char Version[] = "3.0.0";
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{
25863484Sbrian  int f, pos;
25963484Sbrian
26063484Sbrian  *arg->cx->physical->link.lcp.cfg.ident = '\0';
26163484Sbrian
26263484Sbrian  for (pos = 0, f = arg->argn; f < arg->argc; f++)
26363484Sbrian    pos += snprintf(arg->cx->physical->link.lcp.cfg.ident + pos,
26463484Sbrian                    sizeof arg->cx->physical->link.lcp.cfg.ident - pos, "%s%s",
26563484Sbrian                    f == arg->argn ? "" : " ", arg->argv[f]);
26663484Sbrian
26763484Sbrian  return 0;
26863484Sbrian}
26963484Sbrian
27063484Sbrianstatic int
27163484SbrianSendIdentification(struct cmdargs const *arg)
27263484Sbrian{
27363484Sbrian  if (arg->cx->state < DATALINK_LCP) {
27463484Sbrian    log_Printf(LogWARN, "sendident: link has not reached LCP\n");
27563484Sbrian    return 2;
27663484Sbrian  }
27763484Sbrian  return lcp_SendIdentification(&arg->cx->physical->link.lcp) ? 0 : 1;
27863484Sbrian}
27963484Sbrian
28063484Sbrianstatic int
28136285SbrianCloneCommand(struct cmdargs const *arg)
2826059Samurai{
28336285Sbrian  char namelist[LINE_LEN];
28436285Sbrian  char *name;
28536285Sbrian  int f;
2866059Samurai
28736285Sbrian  if (arg->argc == arg->argn)
28836285Sbrian    return -1;
28936285Sbrian
29036285Sbrian  namelist[sizeof namelist - 1] = '\0';
29136285Sbrian  for (f = arg->argn; f < arg->argc; f++) {
29236285Sbrian    strncpy(namelist, arg->argv[f], sizeof namelist - 1);
29336285Sbrian    for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
29436285Sbrian      bundle_DatalinkClone(arg->bundle, arg->cx, name);
2956059Samurai  }
29636285Sbrian
29736285Sbrian  return 0;
2986059Samurai}
2996059Samurai
3006059Samuraistatic int
30136285SbrianRemoveCommand(struct cmdargs const *arg)
3026059Samurai{
30336285Sbrian  if (arg->argc != arg->argn)
30436285Sbrian    return -1;
30511336Samurai
30636285Sbrian  if (arg->cx->state != DATALINK_CLOSED) {
30736285Sbrian    log_Printf(LogWARN, "remove: Cannot delete links that aren't closed\n");
30836285Sbrian    return 2;
3096059Samurai  }
31026516Sbrian
31136285Sbrian  bundle_DatalinkRemove(arg->bundle, arg->cx);
31236285Sbrian  return 0;
31336285Sbrian}
31432711Sbrian
31536285Sbrianstatic int
31636285SbrianRenameCommand(struct cmdargs const *arg)
31736285Sbrian{
31836285Sbrian  if (arg->argc != arg->argn + 1)
31936285Sbrian    return -1;
32031121Sbrian
32136285Sbrian  if (bundle_RenameDatalink(arg->bundle, arg->cx, arg->argv[arg->argn]))
32236285Sbrian    return 0;
32336285Sbrian
32436285Sbrian  log_Printf(LogWARN, "%s -> %s: target name already exists\n",
32536285Sbrian             arg->cx->name, arg->argv[arg->argn]);
32636285Sbrian  return 1;
32736285Sbrian}
32836285Sbrian
32936285Sbrianint
33036285SbrianLoadCommand(struct cmdargs const *arg)
33136285Sbrian{
33240797Sbrian  const char *err;
33340797Sbrian  int n, mode;
33436285Sbrian
33540797Sbrian  mode = arg->bundle->phys_type.all;
33636285Sbrian
33740797Sbrian  if (arg->argn < arg->argc) {
33840797Sbrian    for (n = arg->argn; n < arg->argc; n++)
33940797Sbrian      if ((err = system_IsValid(arg->argv[n], arg->prompt, mode)) != NULL) {
34040797Sbrian        log_Printf(LogWARN, "%s: %s\n", arg->argv[n], err);
34140797Sbrian        return 1;
34240797Sbrian      }
34340797Sbrian
34440797Sbrian    for (n = arg->argn; n < arg->argc; n++) {
34540797Sbrian      bundle_SetLabel(arg->bundle, arg->argv[arg->argc - 1]);
34640797Sbrian      system_Select(arg->bundle, arg->argv[n], CONFFILE, arg->prompt, arg->cx);
34740797Sbrian    }
34840797Sbrian    bundle_SetLabel(arg->bundle, arg->argv[arg->argc - 1]);
34940797Sbrian  } else if ((err = system_IsValid("default", arg->prompt, mode)) != NULL) {
35040797Sbrian    log_Printf(LogWARN, "default: %s\n", err);
35136285Sbrian    return 1;
35236285Sbrian  } else {
35340797Sbrian    bundle_SetLabel(arg->bundle, "default");
35440797Sbrian    system_Select(arg->bundle, "default", CONFFILE, arg->prompt, arg->cx);
35540797Sbrian    bundle_SetLabel(arg->bundle, "default");
35636285Sbrian  }
35740797Sbrian
35826516Sbrian  return 0;
3596059Samurai}
3606059Samurai
36136285Sbrianint
36236285SbrianSaveCommand(struct cmdargs const *arg)
36336285Sbrian{
36436285Sbrian  log_Printf(LogWARN, "save command is not implemented (yet).\n");
36536285Sbrian  return 1;
36636285Sbrian}
36736285Sbrian
36810528Samuraistatic int
36936285SbrianDialCommand(struct cmdargs const *arg)
37028536Sbrian{
37136285Sbrian  int res;
37236285Sbrian
37336465Sbrian  if ((arg->cx && !(arg->cx->physical->type & (PHYS_INTERACTIVE|PHYS_AUTO)))
37436465Sbrian      || (!arg->cx &&
37536928Sbrian          (arg->bundle->phys_type.all & ~(PHYS_INTERACTIVE|PHYS_AUTO)))) {
37636285Sbrian    log_Printf(LogWARN, "Manual dial is only available for auto and"
37736285Sbrian              " interactive links\n");
37836285Sbrian    return 1;
37934536Sbrian  }
38036285Sbrian
38136285Sbrian  if (arg->argc > arg->argn && (res = LoadCommand(arg)) != 0)
38236285Sbrian    return res;
38336285Sbrian
38437993Sbrian  bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1);
38536285Sbrian
38636285Sbrian  return 0;
38728536Sbrian}
38828536Sbrian
38938628Sbrian#define isinword(ch) (isalnum(ch) || (ch) == '_')
39038628Sbrian
39138628Sbrianstatic char *
39238628Sbrianstrstrword(char *big, const char *little)
39338628Sbrian{
39438628Sbrian  /* Get the first occurance of the word ``little'' in ``big'' */
39538628Sbrian  char *pos;
39638628Sbrian  int len;
39738628Sbrian
39838628Sbrian  pos = big;
39938628Sbrian  len = strlen(little);
40038628Sbrian
40138628Sbrian  while ((pos = strstr(pos, little)) != NULL)
40247865Sbrian    if ((pos != big && isinword(pos[-1])) || isinword(pos[len]))
40347865Sbrian      pos++;
40447865Sbrian    else if (pos != big && pos[-1] == '\\')
40547865Sbrian      memmove(pos - 1, pos, strlen(pos) + 1);
40647865Sbrian    else
40738628Sbrian      break;
40838628Sbrian
40938628Sbrian  return pos;
41038628Sbrian}
41138628Sbrian
41238628Sbrianstatic char *
41338628Sbriansubst(char *tgt, const char *oldstr, const char *newstr)
41438628Sbrian{
41538628Sbrian  /* tgt is a malloc()d area... realloc() as necessary */
41638628Sbrian  char *word, *ntgt;
41738628Sbrian  int ltgt, loldstr, lnewstr, pos;
41838628Sbrian
41938628Sbrian  if ((word = strstrword(tgt, oldstr)) == NULL)
42038628Sbrian    return tgt;
42138628Sbrian
42238628Sbrian  ltgt = strlen(tgt) + 1;
42338628Sbrian  loldstr = strlen(oldstr);
42438628Sbrian  lnewstr = strlen(newstr);
42538628Sbrian  do {
42638628Sbrian    pos = word - tgt;
42738628Sbrian    if (loldstr > lnewstr)
42838628Sbrian      bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr);
42938628Sbrian    if (loldstr != lnewstr) {
43038628Sbrian      ntgt = realloc(tgt, ltgt += lnewstr - loldstr);
43138628Sbrian      if (ntgt == NULL)
43238628Sbrian        break;			/* Oh wonderful ! */
43338628Sbrian      word = ntgt + pos;
43438628Sbrian      tgt = ntgt;
43538628Sbrian    }
43638628Sbrian    if (lnewstr > loldstr)
43738628Sbrian      bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr);
43838628Sbrian    bcopy(newstr, word, lnewstr);
43938628Sbrian  } while ((word = strstrword(word, oldstr)));
44038628Sbrian
44138628Sbrian  return tgt;
44238628Sbrian}
44338628Sbrian
44443888Sbrianvoid
44543888Sbriancommand_Expand(char **nargv, int argc, char const *const *oargv,
44647849Sbrian               struct bundle *bundle, int inc0, pid_t pid)
44738628Sbrian{
44838628Sbrian  int arg;
44947849Sbrian  char pidstr[12];
45038628Sbrian
45141755Sbrian  if (inc0)
45241755Sbrian    arg = 0;		/* Start at arg 0 */
45341755Sbrian  else {
45441755Sbrian    nargv[0] = strdup(oargv[0]);
45541755Sbrian    arg = 1;
45641755Sbrian  }
45747849Sbrian  snprintf(pidstr, sizeof pidstr, "%d", (int)pid);
45841755Sbrian  for (; arg < argc; arg++) {
45938629Sbrian    nargv[arg] = strdup(oargv[arg]);
46038629Sbrian    nargv[arg] = subst(nargv[arg], "HISADDR",
46138628Sbrian                       inet_ntoa(bundle->ncp.ipcp.peer_ip));
46281634Sbrian#ifndef NOINET6
46381634Sbrian    nargv[arg] = subst(nargv[arg], "HISADDR6",
46481634Sbrian                       ncpaddr_ntoa(&bundle->ncp.ipv6cp.hisaddr));
46581634Sbrian#endif
46638629Sbrian    nargv[arg] = subst(nargv[arg], "AUTHNAME", bundle->cfg.auth.name);
46740561Sbrian    nargv[arg] = subst(nargv[arg], "INTERFACE", bundle->iface->name);
46838628Sbrian    nargv[arg] = subst(nargv[arg], "MYADDR", inet_ntoa(bundle->ncp.ipcp.my_ip));
46981634Sbrian#ifndef NOINET6
47081634Sbrian    nargv[arg] = subst(nargv[arg], "MYADDR6",
47181634Sbrian                       ncpaddr_ntoa(&bundle->ncp.ipv6cp.myaddr));
47281634Sbrian#endif
47338629Sbrian    nargv[arg] = subst(nargv[arg], "USER", bundle->ncp.mp.peer.authname);
47438629Sbrian    nargv[arg] = subst(nargv[arg], "PEER_ENDDISC",
47538629Sbrian                       mp_Enddisc(bundle->ncp.mp.peer.enddisc.class,
47638629Sbrian                                  bundle->ncp.mp.peer.enddisc.address,
47738629Sbrian                                  bundle->ncp.mp.peer.enddisc.len));
47838629Sbrian    nargv[arg] = subst(nargv[arg], "ENDDISC",
47938629Sbrian                       mp_Enddisc(bundle->ncp.mp.cfg.enddisc.class,
48038629Sbrian                                  bundle->ncp.mp.cfg.enddisc.address,
48138629Sbrian                                  bundle->ncp.mp.cfg.enddisc.len));
48247849Sbrian    nargv[arg] = subst(nargv[arg], "PROCESSID", pidstr);
48338629Sbrian    nargv[arg] = subst(nargv[arg], "LABEL", bundle_GetLabel(bundle));
48458044Sbrian    nargv[arg] = subst(nargv[arg], "DNS0",
48558044Sbrian                       inet_ntoa(bundle->ncp.ipcp.ns.dns[0]));
48658044Sbrian    nargv[arg] = subst(nargv[arg], "DNS1",
48758044Sbrian                       inet_ntoa(bundle->ncp.ipcp.ns.dns[1]));
48863484Sbrian    nargv[arg] = subst(nargv[arg], "VERSION", Version);
48963484Sbrian    nargv[arg] = subst(nargv[arg], "COMPILATIONDATE", __DATE__);
49038628Sbrian  }
49138628Sbrian  nargv[arg] = NULL;
49238628Sbrian}
49338628Sbrian
49428536Sbrianstatic int
49531343SbrianShellCommand(struct cmdargs const *arg, int bg)
49610528Samurai{
49710528Samurai  const char *shell;
49847849Sbrian  pid_t shpid, pid;
49920813Sjkh
50018856Ssos#ifdef SHELL_ONLY_INTERACTIVELY
50126911Sbrian  /* we're only allowed to shell when we run ppp interactively */
50236285Sbrian  if (arg->prompt && arg->prompt->owner) {
50336285Sbrian    log_Printf(LogWARN, "Can't start a shell from a network connection\n");
50426516Sbrian    return 1;
50510528Samurai  }
50626911Sbrian#endif
50728679Sbrian
50836285Sbrian  if (arg->argc == arg->argn) {
50936285Sbrian    if (!arg->prompt) {
51036285Sbrian      log_Printf(LogWARN, "Can't start an interactive shell from"
51136285Sbrian                " a config file\n");
51228381Sbrian      return 1;
51336285Sbrian    } else if (arg->prompt->owner) {
51436285Sbrian      log_Printf(LogWARN, "Can't start an interactive shell from"
51536285Sbrian                " a socket connection\n");
51636285Sbrian      return 1;
51728381Sbrian    } else if (bg) {
51836285Sbrian      log_Printf(LogWARN, "Can only start an interactive shell in"
51928679Sbrian		" the foreground mode\n");
52028381Sbrian      return 1;
52128381Sbrian    }
52234536Sbrian  }
52334536Sbrian
52447849Sbrian  pid = getpid();
52528679Sbrian  if ((shpid = fork()) == 0) {
52636285Sbrian    int i, fd;
52718531Sbde
52836285Sbrian    if ((shell = getenv("SHELL")) == 0)
52936285Sbrian      shell = _PATH_BSHELL;
53032017Sbrian
53136285Sbrian    timer_TermService();
53236285Sbrian
53336285Sbrian    if (arg->prompt)
53436285Sbrian      fd = arg->prompt->fd_out;
53536285Sbrian    else if ((fd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
53636285Sbrian      log_Printf(LogALERT, "Failed to open %s: %s\n",
53736285Sbrian                _PATH_DEVNULL, strerror(errno));
53828679Sbrian      exit(1);
53928679Sbrian    }
54049976Sbrian    dup2(fd, STDIN_FILENO);
54149976Sbrian    dup2(fd, STDOUT_FILENO);
54249976Sbrian    dup2(fd, STDERR_FILENO);
54349976Sbrian    for (i = getdtablesize(); i > STDERR_FILENO; i--)
54449976Sbrian      fcntl(i, F_SETFD, 1);
54526516Sbrian
54664802Sbrian#ifndef NOSUID
54755252Sbrian    setuid(ID0realuid());
54864802Sbrian#endif
54936285Sbrian    if (arg->argc > arg->argn) {
55028679Sbrian      /* substitute pseudo args */
55138628Sbrian      char *argv[MAXARGS];
55238628Sbrian      int argc = arg->argc - arg->argn;
55338628Sbrian
55438628Sbrian      if (argc >= sizeof argv / sizeof argv[0]) {
55538628Sbrian        argc = sizeof argv / sizeof argv[0] - 1;
55638628Sbrian        log_Printf(LogWARN, "Truncating shell command to %d args\n", argc);
55731343Sbrian      }
55847849Sbrian      command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 0, pid);
55928679Sbrian      if (bg) {
56028679Sbrian	pid_t p;
56110528Samurai
56228679Sbrian	p = getpid();
56328679Sbrian	if (daemon(1, 1) == -1) {
56436832Sbrian	  log_Printf(LogERROR, "%d: daemon: %s\n", (int)p, strerror(errno));
56528679Sbrian	  exit(1);
56628679Sbrian	}
56736285Sbrian      } else if (arg->prompt)
56836285Sbrian        printf("ppp: Pausing until %s finishes\n", arg->argv[arg->argn]);
56931343Sbrian      execvp(argv[0], argv);
57030316Sbrian    } else {
57136285Sbrian      if (arg->prompt)
57232017Sbrian        printf("ppp: Pausing until %s finishes\n", shell);
57336285Sbrian      prompt_TtyOldMode(arg->prompt);
57479450Sbrian      execl(shell, shell, (char *)NULL);
57530316Sbrian    }
57620813Sjkh
57740665Sbrian    log_Printf(LogWARN, "exec() of %s failed: %s\n",
57840665Sbrian              arg->argc > arg->argn ? arg->argv[arg->argn] : shell,
57940665Sbrian              strerror(errno));
58049976Sbrian    _exit(255);
58110528Samurai  }
58236285Sbrian
58336285Sbrian  if (shpid == (pid_t) - 1)
58436285Sbrian    log_Printf(LogERROR, "Fork failed: %s\n", strerror(errno));
58536285Sbrian  else {
58610528Samurai    int status;
58731343Sbrian    waitpid(shpid, &status, 0);
58810528Samurai  }
58920813Sjkh
59036285Sbrian  if (arg->prompt && !arg->prompt->owner)
59136285Sbrian    prompt_TtyCommandMode(arg->prompt);
59220813Sjkh
59336285Sbrian  return 0;
59410528Samurai}
59510528Samurai
59631343Sbrianstatic int
59731343SbrianBgShellCommand(struct cmdargs const *arg)
59831343Sbrian{
59936285Sbrian  if (arg->argc == arg->argn)
60031343Sbrian    return -1;
60131343Sbrian  return ShellCommand(arg, 1);
60231343Sbrian}
60331343Sbrian
60431343Sbrianstatic int
60531343SbrianFgShellCommand(struct cmdargs const *arg)
60631343Sbrian{
60731343Sbrian  return ShellCommand(arg, 0);
60831343Sbrian}
60931343Sbrian
61058044Sbrianstatic int
61158044SbrianResolvCommand(struct cmdargs const *arg)
61258044Sbrian{
61358044Sbrian  if (arg->argc == arg->argn + 1) {
61458044Sbrian    if (!strcasecmp(arg->argv[arg->argn], "reload"))
61558044Sbrian      ipcp_LoadDNS(&arg->bundle->ncp.ipcp);
61658044Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "restore"))
61758044Sbrian      ipcp_RestoreDNS(&arg->bundle->ncp.ipcp);
61858044Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "rewrite"))
61958044Sbrian      ipcp_WriteDNS(&arg->bundle->ncp.ipcp);
62058044Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "readonly"))
62158044Sbrian      arg->bundle->ncp.ipcp.ns.writable = 0;
62258044Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "writable"))
62358044Sbrian      arg->bundle->ncp.ipcp.ns.writable = 1;
62458044Sbrian    else
62558044Sbrian      return -1;
62658044Sbrian
62758044Sbrian    return 0;
62858044Sbrian  }
62958044Sbrian
63058044Sbrian  return -1;
63158044Sbrian}
63258044Sbrian
63350059Sbrian#ifndef NONAT
63458867Sbrianstatic struct cmdtab const NatCommands[] =
63540561Sbrian{
63650059Sbrian  {"addr", NULL, nat_RedirectAddr, LOCAL_AUTH,
63750059Sbrian   "static address translation", "nat addr [addr_local addr_alias]"},
63858867Sbrian  {"deny_incoming", NULL, NatOption, LOCAL_AUTH,
63950059Sbrian   "stop incoming connections", "nat deny_incoming yes|no",
64040561Sbrian   (const void *) PKT_ALIAS_DENY_INCOMING},
64158867Sbrian  {"enable", NULL, NatEnable, LOCAL_AUTH,
64250059Sbrian   "enable NAT", "nat enable yes|no"},
64358867Sbrian  {"log", NULL, NatOption, LOCAL_AUTH,
64450059Sbrian   "log NAT link creation", "nat log yes|no",
64540561Sbrian   (const void *) PKT_ALIAS_LOG},
64650059Sbrian  {"port", NULL, nat_RedirectPort, LOCAL_AUTH, "port redirection",
64750059Sbrian   "nat port proto localaddr:port[-port] aliasport[-aliasport]"},
64879433Sbrian  {"proto", NULL, nat_RedirectProto, LOCAL_AUTH, "protocol redirection",
64979433Sbrian   "nat proto proto localIP [publicIP [remoteIP]]"},
65050059Sbrian  {"proxy", NULL, nat_ProxyRule, LOCAL_AUTH,
65150059Sbrian   "proxy control", "nat proxy server host[:port] ..."},
65281033Sbrian#ifndef NO_FW_PUNCH
65381033Sbrian  {"punch_fw", NULL, nat_PunchFW, LOCAL_AUTH,
65481033Sbrian   "firewall control", "nat punch_fw [base count]"},
65581033Sbrian#endif
65658867Sbrian  {"same_ports", NULL, NatOption, LOCAL_AUTH,
65750059Sbrian   "try to leave port numbers unchanged", "nat same_ports yes|no",
65840561Sbrian   (const void *) PKT_ALIAS_SAME_PORTS},
65958867Sbrian  {"target", NULL, nat_SetTarget, LOCAL_AUTH,
66058867Sbrian   "Default address for incoming connections", "nat target addr" },
66158867Sbrian  {"unregistered_only", NULL, NatOption, LOCAL_AUTH,
66250059Sbrian   "translate unregistered (private) IP address space only",
66350059Sbrian   "nat unregistered_only yes|no",
66440561Sbrian   (const void *) PKT_ALIAS_UNREGISTERED_ONLY},
66558867Sbrian  {"use_sockets", NULL, NatOption, LOCAL_AUTH,
66650059Sbrian   "allocate host sockets", "nat use_sockets yes|no",
66740561Sbrian   (const void *) PKT_ALIAS_USE_SOCKETS},
66840561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
66958867Sbrian   "Display this message", "nat help|? [command]", NatCommands},
67040561Sbrian  {NULL, NULL, NULL},
67140561Sbrian};
67240561Sbrian#endif
67340561Sbrian
67440561Sbrianstatic struct cmdtab const AllowCommands[] = {
67540561Sbrian  {"modes", "mode", AllowModes, LOCAL_AUTH,
67640561Sbrian  "Only allow certain ppp modes", "allow modes mode..."},
67740561Sbrian  {"users", "user", AllowUsers, LOCAL_AUTH,
67840561Sbrian  "Only allow ppp access to certain users", "allow users logname..."},
67940561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
68040561Sbrian  "Display this message", "allow help|? [command]", AllowCommands},
68140561Sbrian  {NULL, NULL, NULL},
68240561Sbrian};
68340561Sbrian
68440561Sbrianstatic struct cmdtab const IfaceCommands[] =
68540561Sbrian{
68640561Sbrian  {"add", NULL, IfaceAddCommand, LOCAL_AUTH,
68740561Sbrian   "Add iface address", "iface add addr[/bits| mask] peer", NULL},
68840561Sbrian  {NULL, "add!", IfaceAddCommand, LOCAL_AUTH,
68940561Sbrian   "Add or change an iface address", "iface add! addr[/bits| mask] peer",
69040561Sbrian   (void *)1},
69140561Sbrian  {"clear", NULL, IfaceClearCommand, LOCAL_AUTH,
69281634Sbrian   "Clear iface address(es)", "iface clear [INET | INET6]"},
69340561Sbrian  {"delete", "rm", IfaceDeleteCommand, LOCAL_AUTH,
69440561Sbrian   "Delete iface address", "iface delete addr", NULL},
69540561Sbrian  {NULL, "rm!", IfaceDeleteCommand, LOCAL_AUTH,
69640561Sbrian   "Delete iface address", "iface delete addr", (void *)1},
69740561Sbrian  {NULL, "delete!", IfaceDeleteCommand, LOCAL_AUTH,
69840561Sbrian   "Delete iface address", "iface delete addr", (void *)1},
69940561Sbrian  {"show", NULL, iface_Show, LOCAL_AUTH,
70040561Sbrian   "Show iface address(es)", "iface show"},
70140561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
70250059Sbrian   "Display this message", "nat help|? [command]", IfaceCommands},
70340561Sbrian  {NULL, NULL, NULL},
70440561Sbrian};
70540561Sbrian
70630715Sbrianstatic struct cmdtab const Commands[] = {
70736285Sbrian  {"accept", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
70828679Sbrian  "accept option request", "accept option .."},
70928679Sbrian  {"add", NULL, AddCommand, LOCAL_AUTH,
71032109Sbrian  "add route", "add dest mask gateway", NULL},
71136285Sbrian  {NULL, "add!", AddCommand, LOCAL_AUTH,
71232109Sbrian  "add or change route", "add! dest mask gateway", (void *)1},
71340561Sbrian  {"allow", "auth", RunListCommand, LOCAL_AUTH,
71440561Sbrian  "Allow ppp access", "allow users|modes ....", AllowCommands},
71528679Sbrian  {"bg", "!bg", BgShellCommand, LOCAL_AUTH,
71631372Sbrian  "Run a background command", "[!]bg command"},
71736934Sbrian  {"clear", NULL, ClearCommand, LOCAL_AUTH | LOCAL_CX_OPT,
71846686Sbrian  "Clear throughput statistics",
71981634Sbrian  "clear ipcp|ipv6cp|physical [current|overall|peak]..."},
72036285Sbrian  {"clone", NULL, CloneCommand, LOCAL_AUTH | LOCAL_CX,
72136285Sbrian  "Clone a link", "clone newname..."},
72236285Sbrian  {"close", NULL, CloseCommand, LOCAL_AUTH | LOCAL_CX_OPT,
72336285Sbrian  "Close an FSM", "close [lcp|ccp]"},
72428679Sbrian  {"delete", NULL, DeleteCommand, LOCAL_AUTH,
72532109Sbrian  "delete route", "delete dest", NULL},
72636285Sbrian  {NULL, "delete!", DeleteCommand, LOCAL_AUTH,
72732109Sbrian  "delete a route if it exists", "delete! dest", (void *)1},
72836285Sbrian  {"deny", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
72928679Sbrian  "Deny option request", "deny option .."},
73036285Sbrian  {"dial", "call", DialCommand, LOCAL_AUTH | LOCAL_CX_OPT,
73140797Sbrian  "Dial and login", "dial|call [system ...]", NULL},
73236285Sbrian  {"disable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
73328679Sbrian  "Disable option", "disable option .."},
73436285Sbrian  {"down", NULL, DownCommand, LOCAL_AUTH | LOCAL_CX_OPT,
73546686Sbrian  "Generate a down event", "down [ccp|lcp]"},
73636285Sbrian  {"enable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
73728679Sbrian  "Enable option", "enable option .."},
73863484Sbrian  {"ident", NULL, IdentCommand, LOCAL_AUTH | LOCAL_CX,
73963484Sbrian  "Set the link identity", "ident text..."},
74040561Sbrian  {"iface", "interface", RunListCommand, LOCAL_AUTH,
74140561Sbrian  "interface control", "iface option ...", IfaceCommands},
74236285Sbrian  {"link", "datalink", LinkCommand, LOCAL_AUTH,
74336285Sbrian  "Link specific commands", "link name command ..."},
74437008Sbrian  {"load", NULL, LoadCommand, LOCAL_AUTH | LOCAL_CX_OPT,
74540797Sbrian  "Load settings", "load [system ...]"},
74650059Sbrian#ifndef NONAT
74750059Sbrian  {"nat", "alias", RunListCommand, LOCAL_AUTH,
74858867Sbrian  "NAT control", "nat option yes|no", NatCommands},
74950059Sbrian#endif
75036285Sbrian  {"open", NULL, OpenCommand, LOCAL_AUTH | LOCAL_CX_OPT,
75137955Sbrian  "Open an FSM", "open! [lcp|ccp|ipcp]", (void *)1},
75236285Sbrian  {"passwd", NULL, PasswdCommand, LOCAL_NO_AUTH,
75336285Sbrian  "Password for manipulation", "passwd LocalPassword"},
75436285Sbrian  {"quit", "bye", QuitCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
75536285Sbrian  "Quit PPP program", "quit|bye [all]"},
75636285Sbrian  {"remove", "rm", RemoveCommand, LOCAL_AUTH | LOCAL_CX,
75736285Sbrian  "Remove a link", "remove"},
75836285Sbrian  {"rename", "mv", RenameCommand, LOCAL_AUTH | LOCAL_CX,
75936285Sbrian  "Rename a link", "rename name"},
76058044Sbrian  {"resolv", NULL, ResolvCommand, LOCAL_AUTH,
76158044Sbrian  "Manipulate resolv.conf", "resolv readonly|reload|restore|rewrite|writable"},
76228679Sbrian  {"save", NULL, SaveCommand, LOCAL_AUTH,
76328679Sbrian  "Save settings", "save"},
76463484Sbrian  {"sendident", NULL, SendIdentification, LOCAL_AUTH | LOCAL_CX,
76563484Sbrian  "Transmit the link identity", "sendident"},
76636285Sbrian  {"set", "setup", SetCommand, LOCAL_AUTH | LOCAL_CX_OPT,
76728679Sbrian  "Set parameters", "set[up] var value"},
76828679Sbrian  {"shell", "!", FgShellCommand, LOCAL_AUTH,
76928679Sbrian  "Run a subshell", "shell|! [sh command]"},
77036285Sbrian  {"show", NULL, ShowCommand, LOCAL_AUTH | LOCAL_CX_OPT,
77131372Sbrian  "Show status and stats", "show var"},
77236285Sbrian  {"term", NULL, TerminalCommand, LOCAL_AUTH | LOCAL_CX,
77331372Sbrian  "Enter terminal mode", "term"},
77428679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
77531343Sbrian  "Display this message", "help|? [command]", Commands},
77628679Sbrian  {NULL, NULL, NULL},
7776059Samurai};
7786059Samurai
77928536Sbrianstatic int
78031343SbrianShowEscape(struct cmdargs const *arg)
7816059Samurai{
78236285Sbrian  if (arg->cx->physical->async.cfg.EscMap[32]) {
78336285Sbrian    int code, bit;
78436285Sbrian    const char *sep = "";
7856059Samurai
78626516Sbrian    for (code = 0; code < 32; code++)
78736285Sbrian      if (arg->cx->physical->async.cfg.EscMap[code])
78828679Sbrian	for (bit = 0; bit < 8; bit++)
78936285Sbrian	  if (arg->cx->physical->async.cfg.EscMap[code] & (1 << bit)) {
79036285Sbrian	    prompt_Printf(arg->prompt, "%s0x%02x", sep, (code << 3) + bit);
79136285Sbrian            sep = ", ";
79236285Sbrian          }
79336285Sbrian    prompt_Printf(arg->prompt, "\n");
7946059Samurai  }
79531077Sbrian  return 0;
7966059Samurai}
7976059Samurai
79828679Sbrianstatic int
79936285SbrianShowTimerList(struct cmdargs const *arg)
8006059Samurai{
80136285Sbrian  timer_Show(0, arg->prompt);
80231077Sbrian  return 0;
8036059Samurai}
8046059Samurai
80528679Sbrianstatic int
80631343SbrianShowStopped(struct cmdargs const *arg)
80728327Sbrian{
80836285Sbrian  prompt_Printf(arg->prompt, " Stopped Timer:  LCP: ");
80936285Sbrian  if (!arg->cx->physical->link.lcp.fsm.StoppedTimer.load)
81036285Sbrian    prompt_Printf(arg->prompt, "Disabled");
81128327Sbrian  else
81236285Sbrian    prompt_Printf(arg->prompt, "%ld secs",
81336285Sbrian                  arg->cx->physical->link.lcp.fsm.StoppedTimer.load / SECTICKS);
81428461Sbrian
81536285Sbrian  prompt_Printf(arg->prompt, ", CCP: ");
81636285Sbrian  if (!arg->cx->physical->link.ccp.fsm.StoppedTimer.load)
81736285Sbrian    prompt_Printf(arg->prompt, "Disabled");
81828461Sbrian  else
81936285Sbrian    prompt_Printf(arg->prompt, "%ld secs",
82036285Sbrian                  arg->cx->physical->link.ccp.fsm.StoppedTimer.load / SECTICKS);
82128461Sbrian
82236285Sbrian  prompt_Printf(arg->prompt, "\n");
82328461Sbrian
82431077Sbrian  return 0;
82528327Sbrian}
82628327Sbrian
82728679Sbrianstatic int
82831343SbrianShowVersion(struct cmdargs const *arg)
8296059Samurai{
83051026Sbrian  prompt_Printf(arg->prompt, "PPP Version %s - %s\n", Version, __DATE__);
83131077Sbrian  return 0;
8326059Samurai}
8336059Samurai
83428679Sbrianstatic int
83536285SbrianShowProtocolStats(struct cmdargs const *arg)
83626326Sbrian{
83736285Sbrian  struct link *l = command_ChooseLink(arg);
83826326Sbrian
83936285Sbrian  prompt_Printf(arg->prompt, "%s:\n", l->name);
84036285Sbrian  link_ReportProtocolStatus(l, arg->prompt);
84131077Sbrian  return 0;
84226326Sbrian}
84326326Sbrian
84430715Sbrianstatic struct cmdtab const ShowCommands[] = {
84536285Sbrian  {"bundle", NULL, bundle_ShowStatus, LOCAL_AUTH,
84636285Sbrian  "bundle details", "show bundle"},
84736285Sbrian  {"ccp", NULL, ccp_ReportStatus, LOCAL_AUTH | LOCAL_CX_OPT,
84836285Sbrian  "CCP status", "show cpp"},
84936285Sbrian  {"compress", NULL, sl_Show, LOCAL_AUTH,
85036285Sbrian  "VJ compression stats", "show compress"},
85136285Sbrian  {"escape", NULL, ShowEscape, LOCAL_AUTH | LOCAL_CX,
85236285Sbrian  "escape characters", "show escape"},
85336285Sbrian  {"filter", NULL, filter_Show, LOCAL_AUTH,
85436285Sbrian  "packet filters", "show filter [in|out|dial|alive]"},
85536285Sbrian  {"hdlc", NULL, hdlc_ReportStatus, LOCAL_AUTH | LOCAL_CX,
85636285Sbrian  "HDLC errors", "show hdlc"},
85740561Sbrian  {"iface", "interface", iface_Show, LOCAL_AUTH,
85840561Sbrian  "Interface status", "show iface"},
85936285Sbrian  {"ipcp", NULL, ipcp_Show, LOCAL_AUTH,
86036285Sbrian  "IPCP status", "show ipcp"},
86181634Sbrian#ifndef NOINET6
86281634Sbrian  {"ipv6cp", NULL, ipv6cp_Show, LOCAL_AUTH,
86381634Sbrian  "IPV6CP status", "show ipv6cp"},
86481634Sbrian#endif
86547211Sbrian  {"layers", NULL, link_ShowLayers, LOCAL_AUTH | LOCAL_CX_OPT,
86647211Sbrian  "Protocol layers", "show layers"},
86736285Sbrian  {"lcp", NULL, lcp_ReportStatus, LOCAL_AUTH | LOCAL_CX,
86836285Sbrian  "LCP status", "show lcp"},
86936285Sbrian  {"link", "datalink", datalink_Show, LOCAL_AUTH | LOCAL_CX,
87036285Sbrian  "(high-level) link info", "show link"},
87136285Sbrian  {"links", NULL, bundle_ShowLinks, LOCAL_AUTH,
87236285Sbrian  "available link names", "show links"},
87336285Sbrian  {"log", NULL, log_ShowLevel, LOCAL_AUTH,
87436285Sbrian  "log levels", "show log"},
87536285Sbrian  {"mem", NULL, mbuf_Show, LOCAL_AUTH,
87636285Sbrian  "mbuf allocations", "show mem"},
87781634Sbrian  {"ncp", NULL, ncp_Show, LOCAL_AUTH,
87881634Sbrian  "NCP status", "show ncp"},
87946686Sbrian  {"physical", NULL, physical_ShowStatus, LOCAL_AUTH | LOCAL_CX,
88046686Sbrian  "(low-level) link info", "show physical"},
88136285Sbrian  {"mp", "multilink", mp_ShowStatus, LOCAL_AUTH,
88236285Sbrian  "multilink setup", "show mp"},
88336285Sbrian  {"proto", NULL, ShowProtocolStats, LOCAL_AUTH | LOCAL_CX_OPT,
88436285Sbrian  "protocol summary", "show proto"},
88536285Sbrian  {"route", NULL, route_Show, LOCAL_AUTH,
88636285Sbrian  "routing table", "show route"},
88736285Sbrian  {"stopped", NULL, ShowStopped, LOCAL_AUTH | LOCAL_CX,
88836285Sbrian  "STOPPED timeout", "show stopped"},
88936285Sbrian  {"timers", NULL, ShowTimerList, LOCAL_AUTH,
89036285Sbrian  "alarm timers", "show timers"},
89128679Sbrian  {"version", NULL, ShowVersion, LOCAL_NO_AUTH | LOCAL_AUTH,
89236285Sbrian  "version string", "show version"},
89336285Sbrian  {"who", NULL, log_ShowWho, LOCAL_AUTH,
89436285Sbrian  "client list", "show who"},
89528679Sbrian  {"help", "?", HelpCommand, LOCAL_NO_AUTH | LOCAL_AUTH,
89631343Sbrian  "Display this message", "show help|? [command]", ShowCommands},
89728679Sbrian  {NULL, NULL, NULL},
8986059Samurai};
8996059Samurai
90030715Sbrianstatic struct cmdtab const *
90131343SbrianFindCommand(struct cmdtab const *cmds, const char *str, int *pmatch)
9026059Samurai{
90326516Sbrian  int nmatch;
90426516Sbrian  int len;
90528679Sbrian  struct cmdtab const *found;
9066059Samurai
90726516Sbrian  found = NULL;
90826516Sbrian  len = strlen(str);
90926516Sbrian  nmatch = 0;
9106059Samurai  while (cmds->func) {
91125566Sbrian    if (cmds->name && strncasecmp(str, cmds->name, len) == 0) {
91226516Sbrian      if (cmds->name[len] == '\0') {
91328679Sbrian	*pmatch = 1;
91428679Sbrian	return cmds;
91526516Sbrian      }
9166059Samurai      nmatch++;
9176059Samurai      found = cmds;
91828679Sbrian    } else if (cmds->alias && strncasecmp(str, cmds->alias, len) == 0) {
91926516Sbrian      if (cmds->alias[len] == '\0') {
92028679Sbrian	*pmatch = 1;
92128679Sbrian	return cmds;
92226516Sbrian      }
9236059Samurai      nmatch++;
9246059Samurai      found = cmds;
9256059Samurai    }
9266059Samurai    cmds++;
9276059Samurai  }
9286059Samurai  *pmatch = nmatch;
92926516Sbrian  return found;
9306059Samurai}
9316059Samurai
93236285Sbrianstatic const char *
93336285SbrianmkPrefix(int argc, char const *const *argv, char *tgt, int sz)
93436285Sbrian{
93536285Sbrian  int f, tlen, len;
93636285Sbrian
93736285Sbrian  tlen = 0;
93836285Sbrian  for (f = 0; f < argc && tlen < sz - 2; f++) {
93936285Sbrian    if (f)
94036285Sbrian      tgt[tlen++] = ' ';
94136285Sbrian    len = strlen(argv[f]);
94236285Sbrian    if (len > sz - tlen - 1)
94336285Sbrian      len = sz - tlen - 1;
94436285Sbrian    strncpy(tgt+tlen, argv[f], len);
94536285Sbrian    tlen += len;
94636285Sbrian  }
94736285Sbrian  tgt[tlen] = '\0';
94836285Sbrian  return tgt;
94936285Sbrian}
95036285Sbrian
95130715Sbrianstatic int
95236285SbrianFindExec(struct bundle *bundle, struct cmdtab const *cmds, int argc, int argn,
95336285Sbrian         char const *const *argv, struct prompt *prompt, struct datalink *cx)
9546059Samurai{
95528679Sbrian  struct cmdtab const *cmd;
9566059Samurai  int val = 1;
9576059Samurai  int nmatch;
95831343Sbrian  struct cmdargs arg;
95936285Sbrian  char prefix[100];
9606059Samurai
96136285Sbrian  cmd = FindCommand(cmds, argv[argn], &nmatch);
9626059Samurai  if (nmatch > 1)
96336285Sbrian    log_Printf(LogWARN, "%s: Ambiguous command\n",
96436285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix));
96536285Sbrian  else if (cmd && (!prompt || (cmd->lauth & prompt->auth))) {
96636285Sbrian    if ((cmd->lauth & LOCAL_CX) && !cx)
96736285Sbrian      /* We've got no context, but we require it */
96836285Sbrian      cx = bundle2datalink(bundle, NULL);
96936285Sbrian
97036285Sbrian    if ((cmd->lauth & LOCAL_CX) && !cx)
97136285Sbrian      log_Printf(LogWARN, "%s: No context (use the `link' command)\n",
97236285Sbrian                mkPrefix(argn+1, argv, prefix, sizeof prefix));
97336285Sbrian    else {
97436285Sbrian      if (cx && !(cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
97536285Sbrian        log_Printf(LogWARN, "%s: Redundant context (%s) ignored\n",
97636285Sbrian                  mkPrefix(argn+1, argv, prefix, sizeof prefix), cx->name);
97736285Sbrian        cx = NULL;
97836285Sbrian      }
97936285Sbrian      arg.cmdtab = cmds;
98036285Sbrian      arg.cmd = cmd;
98136285Sbrian      arg.argc = argc;
98236285Sbrian      arg.argn = argn+1;
98336285Sbrian      arg.argv = argv;
98436285Sbrian      arg.bundle = bundle;
98536285Sbrian      arg.cx = cx;
98636285Sbrian      arg.prompt = prompt;
98736285Sbrian      val = (*cmd->func) (&arg);
98836285Sbrian    }
98931343Sbrian  } else
99036285Sbrian    log_Printf(LogWARN, "%s: Invalid command\n",
99136285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix));
99226516Sbrian
99326516Sbrian  if (val == -1)
99436285Sbrian    log_Printf(LogWARN, "Usage: %s\n", cmd->syntax);
99528679Sbrian  else if (val)
99636285Sbrian    log_Printf(LogWARN, "%s: Failed %d\n",
99736285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix), val);
99826516Sbrian
99926516Sbrian  return val;
10006059Samurai}
10016059Samurai
100237009Sbrianint
100358045Sbriancommand_Expand_Interpret(char *buff, int nb, char *argv[MAXARGS], int offset)
100458045Sbrian{
100558045Sbrian  char buff2[LINE_LEN-offset];
100658045Sbrian
100758045Sbrian  InterpretArg(buff, buff2);
100858045Sbrian  strncpy(buff, buff2, LINE_LEN - offset - 1);
100958045Sbrian  buff[LINE_LEN - offset - 1] = '\0';
101058045Sbrian
101158045Sbrian  return command_Interpret(buff, nb, argv);
101258045Sbrian}
101358045Sbrian
101458045Sbrianint
101537009Sbriancommand_Interpret(char *buff, int nb, char *argv[MAXARGS])
10166059Samurai{
10176059Samurai  char *cp;
10186059Samurai
10196059Samurai  if (nb > 0) {
10206059Samurai    cp = buff + strcspn(buff, "\r\n");
10216059Samurai    if (cp)
10226059Samurai      *cp = '\0';
102355145Sbrian    return MakeArgs(buff, argv, MAXARGS, PARSE_REDUCE);
102437009Sbrian  }
102537009Sbrian  return 0;
102631121Sbrian}
10276059Samurai
102831822Sbrianstatic int
102931822Sbrianarghidden(int argc, char const *const *argv, int n)
103031822Sbrian{
103131822Sbrian  /* Is arg n of the given command to be hidden from the log ? */
103231828Sbrian
103331828Sbrian  /* set authkey xxxxx */
103431828Sbrian  /* set key xxxxx */
103531822Sbrian  if (n == 2 && !strncasecmp(argv[0], "se", 2) &&
103631822Sbrian      (!strncasecmp(argv[1], "authk", 5) || !strncasecmp(argv[1], "ke", 2)))
103731822Sbrian    return 1;
103831822Sbrian
103931828Sbrian  /* passwd xxxxx */
104031828Sbrian  if (n == 1 && !strncasecmp(argv[0], "p", 1))
104131828Sbrian    return 1;
104231828Sbrian
104336285Sbrian  /* set server port xxxxx .... */
104436285Sbrian  if (n == 3 && !strncasecmp(argv[0], "se", 2) &&
104536285Sbrian      !strncasecmp(argv[1], "se", 2))
104636285Sbrian    return 1;
104736285Sbrian
104831822Sbrian  return 0;
104931822Sbrian}
105031822Sbrian
105131121Sbrianvoid
105236285Sbriancommand_Run(struct bundle *bundle, int argc, char const *const *argv,
105337008Sbrian           struct prompt *prompt, const char *label, struct datalink *cx)
105431121Sbrian{
105531156Sbrian  if (argc > 0) {
105636285Sbrian    if (log_IsKept(LogCOMMAND)) {
105747844Sbrian      char buf[LINE_LEN];
105831156Sbrian      int f, n;
105931156Sbrian
106031156Sbrian      if (label) {
106131962Sbrian        strncpy(buf, label, sizeof buf - 3);
106231962Sbrian        buf[sizeof buf - 3] = '\0';
106331156Sbrian        strcat(buf, ": ");
106447844Sbrian        n = strlen(buf);
106547844Sbrian      } else {
106647844Sbrian        *buf = '\0';
106747844Sbrian        n = 0;
106831156Sbrian      }
106947844Sbrian      buf[sizeof buf - 1] = '\0';	/* In case we run out of room in buf */
107047844Sbrian
107131156Sbrian      for (f = 0; f < argc; f++) {
107231962Sbrian        if (n < sizeof buf - 1 && f)
107331156Sbrian          buf[n++] = ' ';
107431822Sbrian        if (arghidden(argc, argv, f))
107536285Sbrian          strncpy(buf+n, "********", sizeof buf - n - 1);
107631822Sbrian        else
107731962Sbrian          strncpy(buf+n, argv[f], sizeof buf - n - 1);
107831156Sbrian        n += strlen(buf+n);
107931156Sbrian      }
108036285Sbrian      log_Printf(LogCOMMAND, "%s\n", buf);
108131156Sbrian    }
108237008Sbrian    FindExec(bundle, Commands, argc, 0, argv, prompt, cx);
108331156Sbrian  }
10846059Samurai}
10856059Samurai
108654914Sbrianint
108736285Sbriancommand_Decode(struct bundle *bundle, char *buff, int nb, struct prompt *prompt,
108836285Sbrian              const char *label)
108931121Sbrian{
109031121Sbrian  int argc;
109137009Sbrian  char *argv[MAXARGS];
109231121Sbrian
109358045Sbrian  if ((argc = command_Expand_Interpret(buff, nb, argv, 0)) < 0)
109454914Sbrian    return 0;
109554914Sbrian
109637008Sbrian  command_Run(bundle, argc, (char const *const *)argv, prompt, label, NULL);
109754914Sbrian  return 1;
109831121Sbrian}
109931121Sbrian
11006059Samuraistatic int
110131343SbrianShowCommand(struct cmdargs const *arg)
11026059Samurai{
110336285Sbrian  if (!arg->prompt)
110436285Sbrian    log_Printf(LogWARN, "show: Cannot show without a prompt\n");
110536285Sbrian  else if (arg->argc > arg->argn)
110636285Sbrian    FindExec(arg->bundle, ShowCommands, arg->argc, arg->argn, arg->argv,
110736285Sbrian             arg->prompt, arg->cx);
11086059Samurai  else
110936285Sbrian    prompt_Printf(arg->prompt, "Use ``show ?'' to get a list.\n");
111026516Sbrian
111126516Sbrian  return 0;
11126059Samurai}
11136059Samurai
11146059Samuraistatic int
111531343SbrianTerminalCommand(struct cmdargs const *arg)
11166059Samurai{
111736285Sbrian  if (!arg->prompt) {
111836285Sbrian    log_Printf(LogWARN, "term: Need a prompt\n");
111926516Sbrian    return 1;
11206059Samurai  }
112136285Sbrian
112236285Sbrian  if (arg->cx->physical->link.lcp.fsm.state > ST_CLOSED) {
112336285Sbrian    prompt_Printf(arg->prompt, "LCP state is [%s]\n",
112436285Sbrian                  State2Nam(arg->cx->physical->link.lcp.fsm.state));
112536285Sbrian    return 1;
11266059Samurai  }
112736285Sbrian
112836285Sbrian  datalink_Up(arg->cx, 0, 0);
112936285Sbrian  prompt_TtyTermMode(arg->prompt, arg->cx);
113036285Sbrian  return 0;
11316059Samurai}
11326059Samurai
11336059Samuraistatic int
113431343SbrianQuitCommand(struct cmdargs const *arg)
11356059Samurai{
113636285Sbrian  if (!arg->prompt || prompt_IsController(arg->prompt) ||
113736285Sbrian      (arg->argc > arg->argn && !strcasecmp(arg->argv[arg->argn], "all") &&
113836285Sbrian       (arg->prompt->auth & LOCAL_AUTH)))
113936285Sbrian    Cleanup(EX_NORMAL);
114036285Sbrian  if (arg->prompt)
114136285Sbrian    prompt_Destroy(arg->prompt, 1);
114226516Sbrian
114326516Sbrian  return 0;
11446059Samurai}
11456059Samurai
11466059Samuraistatic int
114736285SbrianOpenCommand(struct cmdargs const *arg)
11486059Samurai{
114937160Sbrian  if (arg->argc == arg->argn)
115037993Sbrian    bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1);
115137160Sbrian  else if (arg->argc == arg->argn + 1) {
115237160Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp")) {
115337385Sbrian      struct datalink *cx = arg->cx ?
115437385Sbrian        arg->cx : bundle2datalink(arg->bundle, NULL);
115537385Sbrian      if (cx) {
115637385Sbrian        if (cx->physical->link.lcp.fsm.state == ST_OPENED)
115737385Sbrian          fsm_Reopen(&cx->physical->link.lcp.fsm);
115837160Sbrian        else
115937993Sbrian          bundle_Open(arg->bundle, cx->name, PHYS_ALL, 1);
116037160Sbrian      } else
116137160Sbrian        log_Printf(LogWARN, "open lcp: You must specify a link\n");
116237160Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) {
116337160Sbrian      struct fsm *fp;
11646059Samurai
116537210Sbrian      fp = &command_ChooseLink(arg)->ccp.fsm;
116637160Sbrian      if (fp->link->lcp.fsm.state != ST_OPENED)
116737160Sbrian        log_Printf(LogWARN, "open: LCP must be open before opening CCP\n");
116837160Sbrian      else if (fp->state == ST_OPENED)
116937160Sbrian        fsm_Reopen(fp);
117037160Sbrian      else {
117137160Sbrian        fp->open_mode = 0;	/* Not passive any more */
117237160Sbrian        if (fp->state == ST_STOPPED) {
117337160Sbrian          fsm_Down(fp);
117437160Sbrian          fsm_Up(fp);
117537160Sbrian        } else {
117637160Sbrian          fsm_Up(fp);
117737160Sbrian          fsm_Open(fp);
117837160Sbrian        }
117936285Sbrian      }
118037160Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ipcp")) {
118137160Sbrian      if (arg->cx)
118237160Sbrian        log_Printf(LogWARN, "open ipcp: You need not specify a link\n");
118337160Sbrian      if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED)
118437160Sbrian        fsm_Reopen(&arg->bundle->ncp.ipcp.fsm);
118537160Sbrian      else
118637993Sbrian        bundle_Open(arg->bundle, NULL, PHYS_ALL, 1);
118737160Sbrian    } else
118837160Sbrian      return -1;
118936285Sbrian  } else
119036285Sbrian    return -1;
119136285Sbrian
119226516Sbrian  return 0;
11936059Samurai}
11946059Samurai
119525067Sbrianstatic int
119636285SbrianCloseCommand(struct cmdargs const *arg)
11976059Samurai{
119837007Sbrian  if (arg->argc == arg->argn)
119937007Sbrian    bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_STAYDOWN);
120037007Sbrian  else if (arg->argc == arg->argn + 1) {
120137007Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp"))
120237007Sbrian      bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_LCP);
120337007Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "ccp") ||
120437007Sbrian             !strcasecmp(arg->argv[arg->argn], "ccp!")) {
120537007Sbrian      struct fsm *fp;
12066059Samurai
120737210Sbrian      fp = &command_ChooseLink(arg)->ccp.fsm;
120837007Sbrian      if (fp->state == ST_OPENED) {
120937007Sbrian        fsm_Close(fp);
121037007Sbrian        if (arg->argv[arg->argn][3] == '!')
121137007Sbrian          fp->open_mode = 0;		/* Stay ST_CLOSED */
121237007Sbrian        else
121337007Sbrian          fp->open_mode = OPEN_PASSIVE;	/* Wait for the peer to start */
121437007Sbrian      }
121537007Sbrian    } else
121636285Sbrian      return -1;
121736285Sbrian  } else
121836285Sbrian    return -1;
121936285Sbrian
122036285Sbrian  return 0;
12216059Samurai}
12226059Samurai
122325067Sbrianstatic int
122436285SbrianDownCommand(struct cmdargs const *arg)
122511336Samurai{
122637018Sbrian  if (arg->argc == arg->argn) {
122737018Sbrian      if (arg->cx)
122837018Sbrian        datalink_Down(arg->cx, CLOSE_STAYDOWN);
122937018Sbrian      else
123037018Sbrian        bundle_Down(arg->bundle, CLOSE_STAYDOWN);
123137018Sbrian  } else if (arg->argc == arg->argn + 1) {
123237018Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp")) {
123337018Sbrian      if (arg->cx)
123437018Sbrian        datalink_Down(arg->cx, CLOSE_LCP);
123537018Sbrian      else
123637018Sbrian        bundle_Down(arg->bundle, CLOSE_LCP);
123737018Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) {
123837018Sbrian      struct fsm *fp = arg->cx ? &arg->cx->physical->link.ccp.fsm :
123937018Sbrian                                 &arg->bundle->ncp.mp.link.ccp.fsm;
124037060Sbrian      fsm2initial(fp);
124137018Sbrian    } else
124237018Sbrian      return -1;
124336285Sbrian  } else
124436285Sbrian    return -1;
124536285Sbrian
124636285Sbrian  return 0;
124725067Sbrian}
124825067Sbrian
124925067Sbrianstatic int
125036285SbrianSetModemSpeed(struct cmdargs const *arg)
125125067Sbrian{
125236285Sbrian  long speed;
125336285Sbrian  char *end;
125411336Samurai
125536285Sbrian  if (arg->argc > arg->argn && *arg->argv[arg->argn]) {
125636285Sbrian    if (arg->argc > arg->argn+1) {
125754917Sbrian      log_Printf(LogWARN, "SetModemSpeed: Too many arguments\n");
125836285Sbrian      return -1;
125911336Samurai    }
126036285Sbrian    if (strcasecmp(arg->argv[arg->argn], "sync") == 0) {
126136285Sbrian      physical_SetSync(arg->cx->physical);
126236285Sbrian      return 0;
126336285Sbrian    }
126436285Sbrian    end = NULL;
126536285Sbrian    speed = strtol(arg->argv[arg->argn], &end, 10);
126636285Sbrian    if (*end) {
126736285Sbrian      log_Printf(LogWARN, "SetModemSpeed: Bad argument \"%s\"",
126836285Sbrian                arg->argv[arg->argn]);
126936285Sbrian      return -1;
127036285Sbrian    }
127136285Sbrian    if (physical_SetSpeed(arg->cx->physical, speed))
127236285Sbrian      return 0;
127336285Sbrian    log_Printf(LogWARN, "%s: Invalid speed\n", arg->argv[arg->argn]);
127436285Sbrian  } else
127536285Sbrian    log_Printf(LogWARN, "SetModemSpeed: No speed specified\n");
127624939Sbrian
127726516Sbrian  return -1;
127811336Samurai}
127911336Samurai
128025067Sbrianstatic int
128131343SbrianSetStoppedTimeout(struct cmdargs const *arg)
128228327Sbrian{
128336285Sbrian  struct link *l = &arg->cx->physical->link;
128436285Sbrian
128536285Sbrian  l->lcp.fsm.StoppedTimer.load = 0;
128636285Sbrian  l->ccp.fsm.StoppedTimer.load = 0;
128736285Sbrian  if (arg->argc <= arg->argn+2) {
128836285Sbrian    if (arg->argc > arg->argn) {
128936285Sbrian      l->lcp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn]) * SECTICKS;
129036285Sbrian      if (arg->argc > arg->argn+1)
129136285Sbrian        l->ccp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn+1]) * SECTICKS;
129228461Sbrian    }
129328327Sbrian    return 0;
129428327Sbrian  }
129528327Sbrian  return -1;
129628327Sbrian}
129728327Sbrian
129828327Sbrianstatic int
129931343SbrianSetServer(struct cmdargs const *arg)
130026940Sbrian{
130126940Sbrian  int res = -1;
130226940Sbrian
130336285Sbrian  if (arg->argc > arg->argn && arg->argc < arg->argn+4) {
130431081Sbrian    const char *port, *passwd, *mask;
130553125Sbrian    int mlen;
130631081Sbrian
130731081Sbrian    /* What's what ? */
130836285Sbrian    port = arg->argv[arg->argn];
130936285Sbrian    if (arg->argc == arg->argn + 2) {
131036285Sbrian      passwd = arg->argv[arg->argn+1];
131136285Sbrian      mask = NULL;
131236285Sbrian    } else if (arg->argc == arg->argn + 3) {
131336285Sbrian      passwd = arg->argv[arg->argn+1];
131436285Sbrian      mask = arg->argv[arg->argn+2];
131553125Sbrian      mlen = strlen(mask);
131653125Sbrian      if (mlen == 0 || mlen > 4 || strspn(mask, "01234567") != mlen ||
131753125Sbrian          (mlen == 4 && *mask != '0')) {
131853125Sbrian        log_Printf(LogWARN, "%s %s: %s: Invalid mask\n",
131953125Sbrian                   arg->argv[arg->argn - 2], arg->argv[arg->argn - 1], mask);
132031081Sbrian        return -1;
132153125Sbrian      }
132271764Sbrian    } else if (arg->argc != arg->argn + 1)
132371764Sbrian      return -1;
132471764Sbrian    else if (strcasecmp(port, "none") == 0) {
132571657Sbrian      if (server_Clear(arg->bundle))
132671657Sbrian        log_Printf(LogPHASE, "Disabled server socket\n");
132771657Sbrian      return 0;
132871657Sbrian    } else if (strcasecmp(port, "open") == 0) {
132971657Sbrian      switch (server_Reopen(arg->bundle)) {
133071657Sbrian        case SERVER_OK:
133171657Sbrian          return 0;
133271657Sbrian        case SERVER_FAILED:
133371764Sbrian          log_Printf(LogWARN, "Failed to reopen server port\n");
133471657Sbrian          return 1;
133571657Sbrian        case SERVER_UNSET:
133671764Sbrian          log_Printf(LogWARN, "Cannot reopen unset server socket\n");
133771657Sbrian          return 1;
133871657Sbrian        default:
133971657Sbrian          break;
134071657Sbrian      }
134171657Sbrian      return -1;
134271657Sbrian    } else if (strcasecmp(port, "closed") == 0) {
134336285Sbrian      if (server_Close(arg->bundle))
134471657Sbrian        log_Printf(LogPHASE, "Closed server socket\n");
134571657Sbrian      else
134671657Sbrian        log_Printf(LogWARN, "Server socket not open\n");
134771657Sbrian
134836285Sbrian      return 0;
134931081Sbrian    } else
135036285Sbrian      return -1;
135131081Sbrian
135271657Sbrian    strncpy(server.cfg.passwd, passwd, sizeof server.cfg.passwd - 1);
135371657Sbrian    server.cfg.passwd[sizeof server.cfg.passwd - 1] = '\0';
135431081Sbrian
135536285Sbrian    if (*port == '/') {
135631081Sbrian      mode_t imask;
135736285Sbrian      char *ptr, name[LINE_LEN + 12];
135828679Sbrian
135953125Sbrian      if (mask == NULL)
136031081Sbrian        imask = (mode_t)-1;
136153125Sbrian      else for (imask = mlen = 0; mask[mlen]; mlen++)
136253125Sbrian        imask = (imask * 8) + mask[mlen] - '0';
136336285Sbrian
136436285Sbrian      ptr = strstr(port, "%d");
136536285Sbrian      if (ptr) {
136636285Sbrian        snprintf(name, sizeof name, "%.*s%d%s",
136737210Sbrian                 (int)(ptr - port), port, arg->bundle->unit, ptr + 2);
136836285Sbrian        port = name;
136936285Sbrian      }
137036285Sbrian      res = server_LocalOpen(arg->bundle, port, imask);
137127346Sbrian    } else {
137236285Sbrian      int iport, add = 0;
137328679Sbrian
137431081Sbrian      if (mask != NULL)
137531081Sbrian        return -1;
137628679Sbrian
137736285Sbrian      if (*port == '+') {
137836285Sbrian        port++;
137936285Sbrian        add = 1;
138036285Sbrian      }
138131081Sbrian      if (strspn(port, "0123456789") != strlen(port)) {
138231081Sbrian        struct servent *s;
138331081Sbrian
138431081Sbrian        if ((s = getservbyname(port, "tcp")) == NULL) {
138531081Sbrian	  iport = 0;
138636285Sbrian	  log_Printf(LogWARN, "%s: Invalid port or service\n", port);
138728679Sbrian	} else
138831081Sbrian	  iport = ntohs(s->s_port);
138927346Sbrian      } else
139031081Sbrian        iport = atoi(port);
139136285Sbrian
139236285Sbrian      if (iport) {
139336285Sbrian        if (add)
139436285Sbrian          iport += arg->bundle->unit;
139536285Sbrian        res = server_TcpOpen(arg->bundle, iport);
139636285Sbrian      } else
139736285Sbrian        res = -1;
139827346Sbrian    }
139931081Sbrian  }
140026940Sbrian
140126940Sbrian  return res;
140226940Sbrian}
140326940Sbrian
140426940Sbrianstatic int
140531343SbrianSetEscape(struct cmdargs const *arg)
14066059Samurai{
14076059Samurai  int code;
140836285Sbrian  int argc = arg->argc - arg->argn;
140936285Sbrian  char const *const *argv = arg->argv + arg->argn;
14106059Samurai
14116059Samurai  for (code = 0; code < 33; code++)
141236285Sbrian    arg->cx->physical->async.cfg.EscMap[code] = 0;
141331343Sbrian
14146059Samurai  while (argc-- > 0) {
14156059Samurai    sscanf(*argv++, "%x", &code);
14166059Samurai    code &= 0xff;
141736285Sbrian    arg->cx->physical->async.cfg.EscMap[code >> 3] |= (1 << (code & 7));
141836285Sbrian    arg->cx->physical->async.cfg.EscMap[32] = 1;
14196059Samurai  }
142026516Sbrian  return 0;
14216059Samurai}
14226059Samurai
14236059Samuraistatic int
142431343SbrianSetInterfaceAddr(struct cmdargs const *arg)
14256059Samurai{
142681634Sbrian  struct ncp *ncp = &arg->bundle->ncp;
142781634Sbrian  struct ncpaddr ncpaddr;
142832267Sbrian  const char *hisaddr;
142932267Sbrian
143040561Sbrian  if (arg->argc > arg->argn + 4)
143140561Sbrian    return -1;
143240561Sbrian
143332267Sbrian  hisaddr = NULL;
143481634Sbrian  memset(&ncp->ipcp.cfg.my_range, '\0', sizeof ncp->ipcp.cfg.my_range);
143581634Sbrian  memset(&ncp->ipcp.cfg.peer_range, '\0', sizeof ncp->ipcp.cfg.peer_range);
143681634Sbrian  ncp->ipcp.cfg.HaveTriggerAddress = 0;
143781634Sbrian  ncp->ipcp.cfg.netmask.s_addr = INADDR_ANY;
143881634Sbrian  iplist_reset(&ncp->ipcp.cfg.peer_list);
143928394Sbrian
144036285Sbrian  if (arg->argc > arg->argn) {
144181634Sbrian    if (!ncprange_aton(&ncp->ipcp.cfg.my_range, ncp, arg->argv[arg->argn]))
144228679Sbrian      return 1;
144336285Sbrian    if (arg->argc > arg->argn+1) {
144436285Sbrian      hisaddr = arg->argv[arg->argn+1];
144536285Sbrian      if (arg->argc > arg->argn+2) {
144681634Sbrian        ncp->ipcp.ifmask = ncp->ipcp.cfg.netmask =
144781634Sbrian          GetIpAddr(arg->argv[arg->argn+2]);
144836285Sbrian	if (arg->argc > arg->argn+3) {
144981634Sbrian	  ncp->ipcp.cfg.TriggerAddress = GetIpAddr(arg->argv[arg->argn+3]);
145081634Sbrian	  ncp->ipcp.cfg.HaveTriggerAddress = 1;
14519440Samurai	}
14526059Samurai      }
14536059Samurai    }
14546059Samurai  }
145528394Sbrian
145640561Sbrian  /* 0.0.0.0 means any address (0 bits) */
145781634Sbrian  ncpaddr_getip4(&ncpaddr, &ncp->ipcp.my_ip);
145881634Sbrian  ncprange_getaddr(&ncp->ipcp.cfg.my_range, &ncpaddr);
145981634Sbrian  if (ncp->ipcp.my_ip.s_addr == INADDR_ANY)
146081634Sbrian    ncprange_setwidth(&ncp->ipcp.cfg.my_range, 0);
146181634Sbrian  bundle_AdjustFilters(arg->bundle, &ncpaddr, NULL);
146236285Sbrian
146336285Sbrian  if (hisaddr && !ipcp_UseHisaddr(arg->bundle, hisaddr,
146436928Sbrian                                  arg->bundle->phys_type.all & PHYS_AUTO))
146532267Sbrian    return 4;
146631121Sbrian
146726516Sbrian  return 0;
14686059Samurai}
14696059Samurai
147018752Sjkhstatic int
147144305SbrianSetRetry(int argc, char const *const *argv, u_int *timeout, u_int *maxreq,
147244305Sbrian          u_int *maxtrm, int def)
147344305Sbrian{
147444305Sbrian  if (argc == 0) {
147544305Sbrian    *timeout = DEF_FSMRETRY;
147644305Sbrian    *maxreq = def;
147744305Sbrian    if (maxtrm != NULL)
147844305Sbrian      *maxtrm = def;
147944305Sbrian  } else {
148044305Sbrian    long l = atol(argv[0]);
148144305Sbrian
148244305Sbrian    if (l < MIN_FSMRETRY) {
148344305Sbrian      log_Printf(LogWARN, "%ld: Invalid FSM retry period - min %d\n",
148444305Sbrian                 l, MIN_FSMRETRY);
148544305Sbrian      return 1;
148644305Sbrian    } else
148744305Sbrian      *timeout = l;
148844305Sbrian
148944305Sbrian    if (argc > 1) {
149044305Sbrian      l = atol(argv[1]);
149144305Sbrian      if (l < 1) {
149244305Sbrian        log_Printf(LogWARN, "%ld: Invalid FSM REQ tries - changed to 1\n", l);
149344305Sbrian        l = 1;
149444305Sbrian      }
149544305Sbrian      *maxreq = l;
149644305Sbrian
149744305Sbrian      if (argc > 2 && maxtrm != NULL) {
149844305Sbrian        l = atol(argv[2]);
149944305Sbrian        if (l < 1) {
150044305Sbrian          log_Printf(LogWARN, "%ld: Invalid FSM TRM tries - changed to 1\n", l);
150144305Sbrian          l = 1;
150244305Sbrian        }
150344305Sbrian        *maxtrm = l;
150444305Sbrian      }
150544305Sbrian    }
150644305Sbrian  }
150744305Sbrian
150844305Sbrian  return 0;
150944305Sbrian}
151044305Sbrian
151144305Sbrianstatic int
151231343SbrianSetVariable(struct cmdargs const *arg)
15136059Samurai{
151437210Sbrian  long long_val, param = (long)arg->cmd->args;
151579119Sbrian  int mode, dummyint, f, first, res;
151678410Sbrian  u_short *change;
151731343Sbrian  const char *argp;
151836285Sbrian  struct datalink *cx = arg->cx;	/* LOCAL_CX uses this */
151936285Sbrian  struct link *l = command_ChooseLink(arg);	/* LOCAL_CX_OPT uses this */
152081634Sbrian  struct in_addr *ipaddr;
152181634Sbrian  struct ncpaddr ncpaddr[2];
15226059Samurai
152336285Sbrian  if (arg->argc > arg->argn)
152436285Sbrian    argp = arg->argv[arg->argn];
152526551Sbrian  else
152631343Sbrian    argp = "";
152726551Sbrian
152879119Sbrian  res = 0;
152979119Sbrian
153036285Sbrian  if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
153136285Sbrian    log_Printf(LogWARN, "set %s: No context (use the `link' command)\n",
153236285Sbrian              arg->cmd->name);
153336285Sbrian    return 1;
153436285Sbrian  } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
153536285Sbrian    log_Printf(LogWARN, "set %s: Redundant context (%s) ignored\n",
153636285Sbrian              arg->cmd->name, cx->name);
153736285Sbrian    cx = NULL;
153836285Sbrian  }
153936285Sbrian
154026551Sbrian  switch (param) {
154128679Sbrian  case VAR_AUTHKEY:
154250139Sbrian    strncpy(arg->bundle->cfg.auth.key, argp,
154350139Sbrian            sizeof arg->bundle->cfg.auth.key - 1);
154450139Sbrian    arg->bundle->cfg.auth.key[sizeof arg->bundle->cfg.auth.key - 1] = '\0';
154528679Sbrian    break;
154637210Sbrian
154728679Sbrian  case VAR_AUTHNAME:
154840622Sbrian    switch (bundle_Phase(arg->bundle)) {
154958880Sbrian      default:
155058880Sbrian        log_Printf(LogWARN, "Altering authname while at phase %s\n",
155158880Sbrian                   bundle_PhaseName(arg->bundle));
155258880Sbrian        /* drop through */
155340622Sbrian      case PHASE_DEAD:
155440622Sbrian      case PHASE_ESTABLISH:
155540622Sbrian        strncpy(arg->bundle->cfg.auth.name, argp,
155640622Sbrian                sizeof arg->bundle->cfg.auth.name - 1);
155740622Sbrian        arg->bundle->cfg.auth.name[sizeof arg->bundle->cfg.auth.name-1] = '\0';
155840622Sbrian        break;
155936285Sbrian    }
156028679Sbrian    break;
156137210Sbrian
156236285Sbrian  case VAR_AUTOLOAD:
156349434Sbrian    if (arg->argc == arg->argn + 3) {
156449434Sbrian      int v1, v2, v3;
156549434Sbrian      char *end;
156649434Sbrian
156749434Sbrian      v1 = strtol(arg->argv[arg->argn], &end, 0);
156849434Sbrian      if (v1 < 0 || *end) {
156949434Sbrian        log_Printf(LogWARN, "autoload: %s: Invalid min percentage\n",
157049434Sbrian                   arg->argv[arg->argn]);
157179119Sbrian        res = 1;
157279119Sbrian        break;
157336285Sbrian      }
157449434Sbrian
157549434Sbrian      v2 = strtol(arg->argv[arg->argn + 1], &end, 0);
157649434Sbrian      if (v2 < 0 || *end) {
157749434Sbrian        log_Printf(LogWARN, "autoload: %s: Invalid max percentage\n",
157849434Sbrian                   arg->argv[arg->argn + 1]);
157979119Sbrian        res = 1;
158079119Sbrian        break;
158149434Sbrian      }
158249434Sbrian      if (v2 < v1) {
158349434Sbrian        v3 = v1;
158449434Sbrian        v1 = v2;
158549434Sbrian        v2 = v3;
158649434Sbrian      }
158749434Sbrian
158849434Sbrian      v3 = strtol(arg->argv[arg->argn + 2], &end, 0);
158949434Sbrian      if (v3 <= 0 || *end) {
159049434Sbrian        log_Printf(LogWARN, "autoload: %s: Invalid throughput period\n",
159149434Sbrian                   arg->argv[arg->argn + 2]);
159279119Sbrian        res = 1;
159379119Sbrian        break;
159449434Sbrian      }
159549434Sbrian
159649434Sbrian      arg->bundle->ncp.mp.cfg.autoload.min = v1;
159749434Sbrian      arg->bundle->ncp.mp.cfg.autoload.max = v2;
159849434Sbrian      arg->bundle->ncp.mp.cfg.autoload.period = v3;
159949434Sbrian      mp_RestartAutoloadTimer(&arg->bundle->ncp.mp);
160036285Sbrian    } else {
160179119Sbrian      log_Printf(LogWARN, "Set autoload requires three arguments\n");
160279119Sbrian      res = 1;
160336285Sbrian    }
160436285Sbrian    break;
160537210Sbrian
160628679Sbrian  case VAR_DIAL:
160736285Sbrian    strncpy(cx->cfg.script.dial, argp, sizeof cx->cfg.script.dial - 1);
160836285Sbrian    cx->cfg.script.dial[sizeof cx->cfg.script.dial - 1] = '\0';
160928679Sbrian    break;
161037210Sbrian
161128679Sbrian  case VAR_LOGIN:
161236285Sbrian    strncpy(cx->cfg.script.login, argp, sizeof cx->cfg.script.login - 1);
161336285Sbrian    cx->cfg.script.login[sizeof cx->cfg.script.login - 1] = '\0';
161428679Sbrian    break;
161537210Sbrian
161636285Sbrian  case VAR_WINSIZE:
161736285Sbrian    if (arg->argc > arg->argn) {
161836285Sbrian      l->ccp.cfg.deflate.out.winsize = atoi(arg->argv[arg->argn]);
161936285Sbrian      if (l->ccp.cfg.deflate.out.winsize < 8 ||
162036285Sbrian          l->ccp.cfg.deflate.out.winsize > 15) {
162136285Sbrian          log_Printf(LogWARN, "%d: Invalid outgoing window size\n",
162236285Sbrian                    l->ccp.cfg.deflate.out.winsize);
162336285Sbrian          l->ccp.cfg.deflate.out.winsize = 15;
162436285Sbrian      }
162536285Sbrian      if (arg->argc > arg->argn+1) {
162636285Sbrian        l->ccp.cfg.deflate.in.winsize = atoi(arg->argv[arg->argn+1]);
162736285Sbrian        if (l->ccp.cfg.deflate.in.winsize < 8 ||
162836285Sbrian            l->ccp.cfg.deflate.in.winsize > 15) {
162936285Sbrian            log_Printf(LogWARN, "%d: Invalid incoming window size\n",
163036285Sbrian                      l->ccp.cfg.deflate.in.winsize);
163136285Sbrian            l->ccp.cfg.deflate.in.winsize = 15;
163236285Sbrian        }
163336285Sbrian      } else
163436285Sbrian        l->ccp.cfg.deflate.in.winsize = 0;
163536285Sbrian    } else {
163679119Sbrian      log_Printf(LogWARN, "No window size specified\n");
163779119Sbrian      res = 1;
163836285Sbrian    }
163936285Sbrian    break;
164037210Sbrian
164167910Sbrian#ifdef HAVE_DES
164278411Sbrian  case VAR_MPPE:
164379119Sbrian    if (arg->argc > arg->argn + 2) {
164479119Sbrian      res = -1;
164579119Sbrian      break;
164679119Sbrian    }
164778411Sbrian
164878411Sbrian    if (arg->argc == arg->argn) {
164978411Sbrian      l->ccp.cfg.mppe.keybits = 0;
165078411Sbrian      l->ccp.cfg.mppe.state = MPPE_ANYSTATE;
165178411Sbrian      l->ccp.cfg.mppe.required = 0;
165278411Sbrian      break;
165378411Sbrian    }
165478411Sbrian
165578411Sbrian    if (!strcmp(argp, "*"))
165678411Sbrian      long_val = 0;
165778411Sbrian    else {
165878411Sbrian      long_val = atol(argp);
165978411Sbrian      if (long_val != 40 && long_val != 56 && long_val != 128) {
166078411Sbrian        log_Printf(LogWARN, "%s: Invalid bits value\n", argp);
166179119Sbrian        res = -1;
166279119Sbrian        break;
166367910Sbrian      }
166467910Sbrian    }
166578411Sbrian
166678411Sbrian    if (arg->argc == arg->argn + 2) {
166778411Sbrian      if (!strcmp(arg->argv[arg->argn + 1], "*"))
166878411Sbrian        l->ccp.cfg.mppe.state = MPPE_ANYSTATE;
166978411Sbrian      else if (!strcasecmp(arg->argv[arg->argn + 1], "stateless"))
167078411Sbrian        l->ccp.cfg.mppe.state = MPPE_STATELESS;
167179370Sbrian      else if (!strcasecmp(arg->argv[arg->argn + 1], "stateful"))
167278411Sbrian        l->ccp.cfg.mppe.state = MPPE_STATEFUL;
167378411Sbrian      else {
167478411Sbrian        log_Printf(LogWARN, "%s: Invalid state value\n",
167578411Sbrian                   arg->argv[arg->argn + 1]);
167679119Sbrian        res = -1;
167779119Sbrian        break;
167878411Sbrian      }
167978411Sbrian    } else
168078411Sbrian      l->ccp.cfg.mppe.state = MPPE_ANYSTATE;
168178411Sbrian    l->ccp.cfg.mppe.keybits = long_val;
168278411Sbrian    l->ccp.cfg.mppe.required = 1;
168367910Sbrian    break;
168467910Sbrian#endif
168567910Sbrian
168628679Sbrian  case VAR_DEVICE:
168736285Sbrian    physical_SetDeviceList(cx->physical, arg->argc - arg->argn,
168836285Sbrian                           arg->argv + arg->argn);
168936285Sbrian    break;
169037210Sbrian
169136285Sbrian  case VAR_ACCMAP:
169236285Sbrian    if (arg->argc > arg->argn) {
169337210Sbrian      u_long ulong_val;
169436285Sbrian      sscanf(argp, "%lx", &ulong_val);
169537210Sbrian      cx->physical->link.lcp.cfg.accmap = (u_int32_t)ulong_val;
169636285Sbrian    } else {
169779119Sbrian      log_Printf(LogWARN, "No accmap specified\n");
169879119Sbrian      res = 1;
169936285Sbrian    }
170036285Sbrian    break;
170137210Sbrian
170236285Sbrian  case VAR_MODE:
170336285Sbrian    mode = Nam2mode(argp);
170436285Sbrian    if (mode == PHYS_NONE || mode == PHYS_ALL) {
170536285Sbrian      log_Printf(LogWARN, "%s: Invalid mode\n", argp);
170679119Sbrian      res = -1;
170779119Sbrian      break;
170836285Sbrian    }
170936285Sbrian    bundle_SetMode(arg->bundle, cx, mode);
171036285Sbrian    break;
171137210Sbrian
171236285Sbrian  case VAR_MRRU:
171340622Sbrian    switch (bundle_Phase(arg->bundle)) {
171440622Sbrian      case PHASE_DEAD:
171540622Sbrian        break;
171640622Sbrian      case PHASE_ESTABLISH:
171740622Sbrian        /* Make sure none of our links are DATALINK_LCP or greater */
171840622Sbrian        if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) {
171940622Sbrian          log_Printf(LogWARN, "mrru: Only changable before LCP negotiations\n");
172079119Sbrian          res = 1;
172179119Sbrian          break;
172240622Sbrian        }
172340622Sbrian        break;
172440622Sbrian      default:
172540622Sbrian        log_Printf(LogWARN, "mrru: Only changable at phase DEAD/ESTABLISH\n");
172679119Sbrian        res = 1;
172779119Sbrian        break;
172829696Sbrian    }
172979119Sbrian    if (res != 0)
173079119Sbrian      break;
173137210Sbrian    long_val = atol(argp);
173237210Sbrian    if (long_val && long_val < MIN_MRU) {
173337210Sbrian      log_Printf(LogWARN, "MRRU %ld: too small - min %d\n", long_val, MIN_MRU);
173479119Sbrian      res = 1;
173579119Sbrian      break;
173637210Sbrian    } else if (long_val > MAX_MRU) {
173737210Sbrian      log_Printf(LogWARN, "MRRU %ld: too big - max %d\n", long_val, MAX_MRU);
173879119Sbrian      res = 1;
173979119Sbrian      break;
174037210Sbrian    } else
174137210Sbrian      arg->bundle->ncp.mp.cfg.mrru = long_val;
174228679Sbrian    break;
174337210Sbrian
174436285Sbrian  case VAR_MRU:
174579163Sbrian    long_val = 0;	/* silence gcc */
174679163Sbrian    change = NULL;	/* silence gcc */
174778410Sbrian    switch(arg->argc - arg->argn) {
174878410Sbrian    case 1:
174979119Sbrian      if (argp[strspn(argp, "0123456789")] != '\0') {
175079119Sbrian        res = -1;
175179119Sbrian        break;
175279119Sbrian      }
175379119Sbrian      /*FALLTHRU*/
175478410Sbrian    case 0:
175578410Sbrian      long_val = atol(argp);
175678410Sbrian      change = &l->lcp.cfg.mru;
175778410Sbrian      if (long_val > l->lcp.cfg.max_mru) {
175878410Sbrian        log_Printf(LogWARN, "MRU %ld: too large - max set to %d\n", long_val,
175978410Sbrian                   l->lcp.cfg.max_mru);
176079119Sbrian        res = 1;
176179119Sbrian        break;
176278410Sbrian      }
176378410Sbrian      break;
176478410Sbrian    case 2:
176579119Sbrian      if (strcasecmp(argp, "max") && strcasecmp(argp, "maximum")) {
176679119Sbrian        res = -1;
176779119Sbrian        break;
176879119Sbrian      }
176978410Sbrian      long_val = atol(arg->argv[arg->argn + 1]);
177078410Sbrian      change = &l->lcp.cfg.max_mru;
177178410Sbrian      if (long_val > MAX_MRU) {
177278410Sbrian        log_Printf(LogWARN, "MRU %ld: too large - maximum is %d\n", long_val,
177378410Sbrian                   MAX_MRU);
177479119Sbrian        res = 1;
177579119Sbrian        break;
177678410Sbrian      }
177778410Sbrian      break;
177878410Sbrian    default:
177979119Sbrian      res = -1;
178079119Sbrian      break;
178178410Sbrian    }
178279119Sbrian    if (res != 0)
178379119Sbrian      break;
178478410Sbrian
178537210Sbrian    if (long_val == 0)
178680385Sbrian      *change = 0;
178737210Sbrian    else if (long_val < MIN_MRU) {
178837210Sbrian      log_Printf(LogWARN, "MRU %ld: too small - min %d\n", long_val, MIN_MRU);
178979119Sbrian      res = 1;
179079119Sbrian      break;
179137210Sbrian    } else if (long_val > MAX_MRU) {
179237210Sbrian      log_Printf(LogWARN, "MRU %ld: too big - max %d\n", long_val, MAX_MRU);
179379119Sbrian      res = 1;
179479119Sbrian      break;
179537210Sbrian    } else
179678410Sbrian      *change = long_val;
179778410Sbrian    if (l->lcp.cfg.mru > *change)
179878410Sbrian      l->lcp.cfg.mru = *change;
179928679Sbrian    break;
180037210Sbrian
180136285Sbrian  case VAR_MTU:
180279163Sbrian    long_val = 0;	/* silence gcc */
180379163Sbrian    change = NULL;	/* silence gcc */
180478410Sbrian    switch(arg->argc - arg->argn) {
180578410Sbrian    case 1:
180679119Sbrian      if (argp[strspn(argp, "0123456789")] != '\0') {
180779119Sbrian        res = -1;
180879119Sbrian        break;
180979119Sbrian      }
181079119Sbrian      /*FALLTHRU*/
181178410Sbrian    case 0:
181278410Sbrian      long_val = atol(argp);
181378410Sbrian      change = &l->lcp.cfg.mtu;
181478410Sbrian      if (long_val > l->lcp.cfg.max_mtu) {
181578410Sbrian        log_Printf(LogWARN, "MTU %ld: too large - max set to %d\n", long_val,
181678410Sbrian                   l->lcp.cfg.max_mtu);
181779119Sbrian        res = 1;
181879119Sbrian        break;
181978410Sbrian      }
182078410Sbrian      break;
182178410Sbrian    case 2:
182279119Sbrian      if (strcasecmp(argp, "max") && strcasecmp(argp, "maximum")) {
182379119Sbrian        res = -1;
182479119Sbrian        break;
182579119Sbrian      }
182678410Sbrian      long_val = atol(arg->argv[arg->argn + 1]);
182778410Sbrian      change = &l->lcp.cfg.max_mtu;
182878410Sbrian      if (long_val > MAX_MTU) {
182978410Sbrian        log_Printf(LogWARN, "MTU %ld: too large - maximum is %d\n", long_val,
183078410Sbrian                   MAX_MTU);
183179119Sbrian        res = 1;
183279119Sbrian        break;
183378410Sbrian      }
183478410Sbrian      break;
183578410Sbrian    default:
183679119Sbrian      res = -1;
183779119Sbrian      break;
183878410Sbrian    }
183978410Sbrian
184079119Sbrian    if (res != 0)
184179119Sbrian      break;
184279119Sbrian
184337210Sbrian    if (long_val && long_val < MIN_MTU) {
184437210Sbrian      log_Printf(LogWARN, "MTU %ld: too small - min %d\n", long_val, MIN_MTU);
184579119Sbrian      res = 1;
184679119Sbrian      break;
184737210Sbrian    } else if (long_val > MAX_MTU) {
184837210Sbrian      log_Printf(LogWARN, "MTU %ld: too big - max %d\n", long_val, MAX_MTU);
184979119Sbrian      res = 1;
185079119Sbrian      break;
185137210Sbrian    } else
185278410Sbrian      *change = long_val;
185378410Sbrian    if (l->lcp.cfg.mtu > *change)
185478410Sbrian      l->lcp.cfg.mtu = *change;
185536285Sbrian    break;
185637210Sbrian
185736285Sbrian  case VAR_OPENMODE:
185836285Sbrian    if (strcasecmp(argp, "active") == 0)
185936285Sbrian      cx->physical->link.lcp.cfg.openmode = arg->argc > arg->argn+1 ?
186036285Sbrian        atoi(arg->argv[arg->argn+1]) : 1;
186136285Sbrian    else if (strcasecmp(argp, "passive") == 0)
186236285Sbrian      cx->physical->link.lcp.cfg.openmode = OPEN_PASSIVE;
186336285Sbrian    else {
186479119Sbrian      log_Printf(LogWARN, "%s: Invalid openmode\n", argp);
186579119Sbrian      res = 1;
186636285Sbrian    }
186736285Sbrian    break;
186837210Sbrian
186928679Sbrian  case VAR_PHONE:
187036285Sbrian    strncpy(cx->cfg.phone.list, argp, sizeof cx->cfg.phone.list - 1);
187136285Sbrian    cx->cfg.phone.list[sizeof cx->cfg.phone.list - 1] = '\0';
187238174Sbrian    cx->phone.alt = cx->phone.next = NULL;
187328679Sbrian    break;
187437210Sbrian
187528679Sbrian  case VAR_HANGUP:
187636285Sbrian    strncpy(cx->cfg.script.hangup, argp, sizeof cx->cfg.script.hangup - 1);
187736285Sbrian    cx->cfg.script.hangup[sizeof cx->cfg.script.hangup - 1] = '\0';
187828679Sbrian    break;
187937210Sbrian
188061534Sbrian  case VAR_IFQUEUE:
188161534Sbrian    long_val = atol(argp);
188261534Sbrian    arg->bundle->cfg.ifqueue = long_val < 0 ? 0 : long_val;
188361534Sbrian    break;
188461534Sbrian
188552488Sbrian  case VAR_LOGOUT:
188652488Sbrian    strncpy(cx->cfg.script.logout, argp, sizeof cx->cfg.script.logout - 1);
188752488Sbrian    cx->cfg.script.logout[sizeof cx->cfg.script.logout - 1] = '\0';
188852488Sbrian    break;
188952488Sbrian
189036285Sbrian  case VAR_IDLETIMEOUT:
189179119Sbrian    if (arg->argc > arg->argn+2) {
189279119Sbrian      log_Printf(LogWARN, "Too many idle timeout values\n");
189379119Sbrian      res = 1;
189479119Sbrian    } else if (arg->argc == arg->argn) {
189579119Sbrian      log_Printf(LogWARN, "Too few idle timeout values\n");
189679119Sbrian      res = 1;
189779119Sbrian    } else {
189849978Sbrian      int timeout, min;
189949978Sbrian
190049978Sbrian      timeout = atoi(argp);
190149978Sbrian      min = arg->argc == arg->argn + 2 ? atoi(arg->argv[arg->argn + 1]) : -1;
190249978Sbrian      bundle_SetIdleTimer(arg->bundle, timeout, min);
190349978Sbrian    }
190429549Sbrian    break;
190537210Sbrian
190636285Sbrian  case VAR_LQRPERIOD:
190737210Sbrian    long_val = atol(argp);
190837210Sbrian    if (long_val < MIN_LQRPERIOD) {
190937210Sbrian      log_Printf(LogWARN, "%ld: Invalid lqr period - min %d\n",
191037210Sbrian                 long_val, MIN_LQRPERIOD);
191179119Sbrian      res = 1;
191236285Sbrian    } else
191337210Sbrian      l->lcp.cfg.lqrperiod = long_val;
191436285Sbrian    break;
191537210Sbrian
191636285Sbrian  case VAR_LCPRETRY:
191779119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
191879119Sbrian                   &cx->physical->link.lcp.cfg.fsm.timeout,
191979119Sbrian                   &cx->physical->link.lcp.cfg.fsm.maxreq,
192079119Sbrian                   &cx->physical->link.lcp.cfg.fsm.maxtrm, DEF_FSMTRIES);
192136285Sbrian    break;
192237210Sbrian
192336285Sbrian  case VAR_CHAPRETRY:
192479119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
192579119Sbrian                   &cx->chap.auth.cfg.fsm.timeout,
192679119Sbrian                   &cx->chap.auth.cfg.fsm.maxreq, NULL, DEF_FSMAUTHTRIES);
192736285Sbrian    break;
192837210Sbrian
192936285Sbrian  case VAR_PAPRETRY:
193079119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
193179119Sbrian                   &cx->pap.cfg.fsm.timeout, &cx->pap.cfg.fsm.maxreq,
193279119Sbrian                   NULL, DEF_FSMAUTHTRIES);
193336285Sbrian    break;
193437210Sbrian
193536285Sbrian  case VAR_CCPRETRY:
193679119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
193779119Sbrian                   &l->ccp.cfg.fsm.timeout, &l->ccp.cfg.fsm.maxreq,
193879119Sbrian                   &l->ccp.cfg.fsm.maxtrm, DEF_FSMTRIES);
193936285Sbrian    break;
194037210Sbrian
194136285Sbrian  case VAR_IPCPRETRY:
194279119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
194379119Sbrian                   &arg->bundle->ncp.ipcp.cfg.fsm.timeout,
194479119Sbrian                   &arg->bundle->ncp.ipcp.cfg.fsm.maxreq,
194579119Sbrian                   &arg->bundle->ncp.ipcp.cfg.fsm.maxtrm, DEF_FSMTRIES);
194636285Sbrian    break;
194737210Sbrian
194836285Sbrian  case VAR_NBNS:
194936285Sbrian  case VAR_DNS:
195058044Sbrian    if (param == VAR_DNS) {
195181634Sbrian      ipaddr = arg->bundle->ncp.ipcp.cfg.ns.dns;
195281634Sbrian      ipaddr[0].s_addr = ipaddr[1].s_addr = INADDR_NONE;
195358044Sbrian    } else {
195481634Sbrian      ipaddr = arg->bundle->ncp.ipcp.cfg.ns.nbns;
195581634Sbrian      ipaddr[0].s_addr = ipaddr[1].s_addr = INADDR_ANY;
195658044Sbrian    }
195736285Sbrian
195836285Sbrian    if (arg->argc > arg->argn) {
195981634Sbrian      ncpaddr_aton(ncpaddr, &arg->bundle->ncp, arg->argv[arg->argn]);
196081634Sbrian      if (!ncpaddr_getip4(ncpaddr, ipaddr))
196181634Sbrian        return -1;
196281634Sbrian      if (arg->argc > arg->argn+1) {
196381634Sbrian        ncpaddr_aton(ncpaddr + 1, &arg->bundle->ncp, arg->argv[arg->argn + 1]);
196481634Sbrian        if (!ncpaddr_getip4(ncpaddr + 1, ipaddr + 1))
196581634Sbrian          return -1;
196681634Sbrian      }
196736285Sbrian
196881634Sbrian      if (ipaddr[0].s_addr == INADDR_ANY) {
196981634Sbrian        ipaddr[0] = ipaddr[1];
197081634Sbrian        ipaddr[1].s_addr = INADDR_ANY;
197158044Sbrian      }
197281634Sbrian      if (ipaddr[0].s_addr == INADDR_NONE) {
197381634Sbrian        ipaddr[0] = ipaddr[1];
197481634Sbrian        ipaddr[1].s_addr = INADDR_NONE;
197558044Sbrian      }
197636285Sbrian    }
197736285Sbrian    break;
197838174Sbrian
197938174Sbrian  case VAR_CALLBACK:
198038174Sbrian    cx->cfg.callback.opmask = 0;
198138174Sbrian    for (dummyint = arg->argn; dummyint < arg->argc; dummyint++) {
198238174Sbrian      if (!strcasecmp(arg->argv[dummyint], "auth"))
198338174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_AUTH);
198438174Sbrian      else if (!strcasecmp(arg->argv[dummyint], "cbcp"))
198538174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_CBCP);
198638174Sbrian      else if (!strcasecmp(arg->argv[dummyint], "e.164")) {
198738174Sbrian        if (dummyint == arg->argc - 1)
198838174Sbrian          log_Printf(LogWARN, "No E.164 arg (E.164 ignored) !\n");
198938174Sbrian        else {
199038174Sbrian          cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_E164);
199138174Sbrian          strncpy(cx->cfg.callback.msg, arg->argv[++dummyint],
199238174Sbrian                  sizeof cx->cfg.callback.msg - 1);
199338174Sbrian          cx->cfg.callback.msg[sizeof cx->cfg.callback.msg - 1] = '\0';
199438174Sbrian        }
199538174Sbrian      } else if (!strcasecmp(arg->argv[dummyint], "none"))
199638174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_NONE);
199779119Sbrian      else {
199879119Sbrian        res = -1;
199979119Sbrian        break;
200079119Sbrian      }
200138174Sbrian    }
200238174Sbrian    if (cx->cfg.callback.opmask == CALLBACK_BIT(CALLBACK_NONE))
200338174Sbrian      cx->cfg.callback.opmask = 0;
200438174Sbrian    break;
200538174Sbrian
200638174Sbrian  case VAR_CBCP:
200738174Sbrian    cx->cfg.cbcp.delay = 0;
200838174Sbrian    *cx->cfg.cbcp.phone = '\0';
200938174Sbrian    cx->cfg.cbcp.fsmretry = DEF_FSMRETRY;
201038174Sbrian    if (arg->argc > arg->argn) {
201138174Sbrian      strncpy(cx->cfg.cbcp.phone, arg->argv[arg->argn],
201238174Sbrian              sizeof cx->cfg.cbcp.phone - 1);
201338174Sbrian      cx->cfg.cbcp.phone[sizeof cx->cfg.cbcp.phone - 1] = '\0';
201438174Sbrian      if (arg->argc > arg->argn + 1) {
201538174Sbrian        cx->cfg.cbcp.delay = atoi(arg->argv[arg->argn + 1]);
201638174Sbrian        if (arg->argc > arg->argn + 2) {
201738174Sbrian          long_val = atol(arg->argv[arg->argn + 2]);
201838174Sbrian          if (long_val < MIN_FSMRETRY)
201938174Sbrian            log_Printf(LogWARN, "%ld: Invalid CBCP FSM retry period - min %d\n",
202038174Sbrian                       long_val, MIN_FSMRETRY);
202138174Sbrian          else
202238174Sbrian            cx->cfg.cbcp.fsmretry = long_val;
202338174Sbrian        }
202438174Sbrian      }
202538174Sbrian    }
202638174Sbrian    break;
202738544Sbrian
202838544Sbrian  case VAR_CHOKED:
202938544Sbrian    arg->bundle->cfg.choked.timeout = atoi(argp);
203038544Sbrian    if (arg->bundle->cfg.choked.timeout <= 0)
203138544Sbrian      arg->bundle->cfg.choked.timeout = CHOKED_TIMEOUT;
203238544Sbrian    break;
203340665Sbrian
203440665Sbrian  case VAR_SENDPIPE:
203540665Sbrian    long_val = atol(argp);
203681634Sbrian    arg->bundle->ncp.cfg.sendpipe = long_val;
203740665Sbrian    break;
203840665Sbrian
203940665Sbrian  case VAR_RECVPIPE:
204040665Sbrian    long_val = atol(argp);
204181634Sbrian    arg->bundle->ncp.cfg.recvpipe = long_val;
204240665Sbrian    break;
204343313Sbrian
204443313Sbrian#ifndef NORADIUS
204543313Sbrian  case VAR_RADIUS:
204643313Sbrian    if (!*argp)
204743313Sbrian      *arg->bundle->radius.cfg.file = '\0';
204843313Sbrian    else if (access(argp, R_OK)) {
204943313Sbrian      log_Printf(LogWARN, "%s: %s\n", argp, strerror(errno));
205079119Sbrian      res = 1;
205179119Sbrian      break;
205243313Sbrian    } else {
205343313Sbrian      strncpy(arg->bundle->radius.cfg.file, argp,
205443313Sbrian              sizeof arg->bundle->radius.cfg.file - 1);
205543313Sbrian      arg->bundle->radius.cfg.file
205643313Sbrian        [sizeof arg->bundle->radius.cfg.file - 1] = '\0';
205743313Sbrian    }
205843313Sbrian    break;
205943313Sbrian#endif
206044073Sbrian
206144073Sbrian  case VAR_CD:
206244073Sbrian    if (*argp) {
206351699Sbrian      if (strcasecmp(argp, "off")) {
206451699Sbrian        long_val = atol(argp);
206551699Sbrian        if (long_val < 0)
206651699Sbrian          long_val = 0;
206751699Sbrian        cx->physical->cfg.cd.delay = long_val;
206851699Sbrian        cx->physical->cfg.cd.necessity = argp[strlen(argp)-1] == '!' ?
206951699Sbrian          CD_REQUIRED : CD_VARIABLE;
207051699Sbrian      } else
207151699Sbrian        cx->physical->cfg.cd.necessity = CD_NOTREQUIRED;
207244073Sbrian    } else {
207353733Sbrian      cx->physical->cfg.cd.delay = 0;
207453733Sbrian      cx->physical->cfg.cd.necessity = CD_DEFAULT;
207544073Sbrian    }
207644073Sbrian    break;
207736285Sbrian
207846686Sbrian  case VAR_PARITY:
207946686Sbrian    if (arg->argc == arg->argn + 1)
208079119Sbrian      res = physical_SetParity(arg->cx->physical, argp);
208146686Sbrian    else {
208279119Sbrian      log_Printf(LogWARN, "Parity value must be odd, even or none\n");
208379119Sbrian      res = 1;
208446686Sbrian    }
208546686Sbrian    break;
20866059Samurai
208746686Sbrian  case VAR_CRTSCTS:
208846686Sbrian    if (strcasecmp(argp, "on") == 0)
208936285Sbrian      physical_SetRtsCts(arg->cx->physical, 1);
209046686Sbrian    else if (strcasecmp(argp, "off") == 0)
209136285Sbrian      physical_SetRtsCts(arg->cx->physical, 0);
209246686Sbrian    else {
209379119Sbrian      log_Printf(LogWARN, "RTS/CTS value must be on or off\n");
209479119Sbrian      res = 1;
209546686Sbrian    }
209646686Sbrian    break;
209750867Sbrian
209850867Sbrian  case VAR_URGENTPORTS:
209951048Sbrian    if (arg->argn == arg->argc) {
210081634Sbrian      ncp_SetUrgentTOS(&arg->bundle->ncp);
210181634Sbrian      ncp_ClearUrgentTcpPorts(&arg->bundle->ncp);
210281634Sbrian      ncp_ClearUrgentUdpPorts(&arg->bundle->ncp);
210351048Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "udp")) {
210481634Sbrian      ncp_SetUrgentTOS(&arg->bundle->ncp);
210551048Sbrian      if (arg->argn == arg->argc - 1)
210681634Sbrian        ncp_ClearUrgentUdpPorts(&arg->bundle->ncp);
210751048Sbrian      else for (f = arg->argn + 1; f < arg->argc; f++)
210851048Sbrian        if (*arg->argv[f] == '+')
210981634Sbrian          ncp_AddUrgentUdpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1));
211051048Sbrian        else if (*arg->argv[f] == '-')
211181634Sbrian          ncp_RemoveUrgentUdpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1));
211251048Sbrian        else {
211351048Sbrian          if (f == arg->argn)
211481634Sbrian            ncp_ClearUrgentUdpPorts(&arg->bundle->ncp);
211581634Sbrian          ncp_AddUrgentUdpPort(&arg->bundle->ncp, atoi(arg->argv[f]));
211651048Sbrian        }
211761430Sbrian    } else if (arg->argn == arg->argc - 1 &&
211861430Sbrian               !strcasecmp(arg->argv[arg->argn], "none")) {
211981634Sbrian      ncp_ClearUrgentTcpPorts(&arg->bundle->ncp);
212081634Sbrian      ncp_ClearUrgentUdpPorts(&arg->bundle->ncp);
212181634Sbrian      ncp_ClearUrgentTOS(&arg->bundle->ncp);
212251048Sbrian    } else {
212381634Sbrian      ncp_SetUrgentTOS(&arg->bundle->ncp);
212451048Sbrian      first = arg->argn;
212551048Sbrian      if (!strcasecmp(arg->argv[first], "tcp") && ++first == arg->argc)
212681634Sbrian        ncp_ClearUrgentTcpPorts(&arg->bundle->ncp);
212751048Sbrian
212851048Sbrian      for (f = first; f < arg->argc; f++)
212951048Sbrian        if (*arg->argv[f] == '+')
213081634Sbrian          ncp_AddUrgentTcpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1));
213151048Sbrian        else if (*arg->argv[f] == '-')
213281634Sbrian          ncp_RemoveUrgentTcpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1));
213351048Sbrian        else {
213451048Sbrian          if (f == first)
213581634Sbrian            ncp_ClearUrgentTcpPorts(&arg->bundle->ncp);
213681634Sbrian          ncp_AddUrgentTcpPort(&arg->bundle->ncp, atoi(arg->argv[f]));
213751048Sbrian        }
213851048Sbrian    }
213950867Sbrian    break;
214020812Sjkh  }
214146686Sbrian
214279119Sbrian  return res;
214320812Sjkh}
214420812Sjkh
214530715Sbrianstatic struct cmdtab const SetCommands[] = {
214636285Sbrian  {"accmap", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
214736285Sbrian  "accmap value", "set accmap hex-value", (const void *)VAR_ACCMAP},
214828679Sbrian  {"authkey", "key", SetVariable, LOCAL_AUTH,
214936285Sbrian  "authentication key", "set authkey|key key", (const void *)VAR_AUTHKEY},
215028679Sbrian  {"authname", NULL, SetVariable, LOCAL_AUTH,
215136285Sbrian  "authentication name", "set authname name", (const void *)VAR_AUTHNAME},
215236285Sbrian  {"autoload", NULL, SetVariable, LOCAL_AUTH,
215336285Sbrian  "auto link [de]activation", "set autoload maxtime maxload mintime minload",
215436285Sbrian  (const void *)VAR_AUTOLOAD},
215550867Sbrian  {"bandwidth", NULL, mp_SetDatalinkBandwidth, LOCAL_AUTH | LOCAL_CX,
215650867Sbrian  "datalink bandwidth", "set bandwidth value"},
215738174Sbrian  {"callback", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
215838174Sbrian  "callback control", "set callback [none|auth|cbcp|"
215938174Sbrian  "E.164 *|number[,number]...]...", (const void *)VAR_CALLBACK},
216038174Sbrian  {"cbcp", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
216138174Sbrian  "CBCP control", "set cbcp [*|phone[,phone...] [delay [timeout]]]",
216238174Sbrian  (const void *)VAR_CBCP},
216344305Sbrian  {"ccpretry", "ccpretries", SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
216444305Sbrian   "CCP retries", "set ccpretry value [attempts]", (const void *)VAR_CCPRETRY},
216544073Sbrian  {"cd", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "Carrier delay requirement",
216644073Sbrian   "set cd value[!]", (const void *)VAR_CD},
216744305Sbrian  {"chapretry", "chapretries", SetVariable, LOCAL_AUTH | LOCAL_CX,
216844305Sbrian   "CHAP retries", "set chapretry value [attempts]",
216944305Sbrian   (const void *)VAR_CHAPRETRY},
217038544Sbrian  {"choked", NULL, SetVariable, LOCAL_AUTH,
217138544Sbrian  "choked timeout", "set choked [secs]", (const void *)VAR_CHOKED},
217246686Sbrian  {"ctsrts", "crtscts", SetVariable, LOCAL_AUTH | LOCAL_CX,
217346686Sbrian   "Use hardware flow control", "set ctsrts [on|off]",
217446686Sbrian   (const char *)VAR_CRTSCTS},
217536285Sbrian  {"deflate", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
217636285Sbrian  "deflate window sizes", "set deflate out-winsize in-winsize",
217736285Sbrian  (const void *) VAR_WINSIZE},
217867910Sbrian#ifdef HAVE_DES
217967910Sbrian  {"mppe", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
218079370Sbrian  "MPPE key size and state", "set mppe [40|56|128|* [stateful|stateless|*]]",
218178411Sbrian  (const void *) VAR_MPPE},
218267910Sbrian#endif
218336285Sbrian  {"device", "line", SetVariable, LOCAL_AUTH | LOCAL_CX,
218446686Sbrian  "physical device name", "set device|line device-name[,device-name]",
218536285Sbrian  (const void *) VAR_DEVICE},
218636285Sbrian  {"dial", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
218736285Sbrian  "dialing script", "set dial chat-script", (const void *) VAR_DIAL},
218836285Sbrian  {"dns", NULL, SetVariable, LOCAL_AUTH, "Domain Name Server",
218936285Sbrian  "set dns pri-addr [sec-addr]", (const void *)VAR_DNS},
219036285Sbrian  {"enddisc", NULL, mp_SetEnddisc, LOCAL_AUTH,
219136285Sbrian  "Endpoint Discriminator", "set enddisc [IP|magic|label|psn value]"},
219236285Sbrian  {"escape", NULL, SetEscape, LOCAL_AUTH | LOCAL_CX,
219336285Sbrian  "escape characters", "set escape hex-digit ..."},
219436285Sbrian  {"filter", NULL, filter_Set, LOCAL_AUTH,
219536285Sbrian  "packet filters", "set filter alive|dial|in|out rule-no permit|deny "
219681634Sbrian  "[src_addr[/width]] [dst_addr[/width]] [proto "
219748142Sbrian  "[src [lt|eq|gt port]] [dst [lt|eq|gt port]] [estab] [syn] [finrst]]"},
219836285Sbrian  {"hangup", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
219936285Sbrian  "hangup script", "set hangup chat-script", (const void *) VAR_HANGUP},
220036285Sbrian  {"ifaddr", NULL, SetInterfaceAddr, LOCAL_AUTH, "destination address",
220131343Sbrian  "set ifaddr [src-addr [dst-addr [netmask [trg-addr]]]]"},
220261534Sbrian  {"ifqueue", NULL, SetVariable, LOCAL_AUTH, "interface queue",
220361534Sbrian  "set ifqueue packets", (const void *)VAR_IFQUEUE},
220444305Sbrian  {"ipcpretry", "ipcpretries", SetVariable, LOCAL_AUTH, "IPCP retries",
220544305Sbrian   "set ipcpretry value [attempts]", (const void *)VAR_IPCPRETRY},
220644305Sbrian  {"lcpretry", "lcpretries", SetVariable, LOCAL_AUTH | LOCAL_CX, "LCP retries",
220744305Sbrian   "set lcpretry value [attempts]", (const void *)VAR_LCPRETRY},
220836712Sbrian  {"log", NULL, log_SetLevel, LOCAL_AUTH, "log level",
220967916Sbrian  "set log [local] [+|-]all|async|cbcp|ccp|chat|command|connect|debug|dns|hdlc|"
221058033Sbrian  "id0|ipcp|lcp|lqm|phase|physical|sync|tcp/ip|timer|tun..."},
221136285Sbrian  {"login", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
221236285Sbrian  "login script", "set login chat-script", (const void *) VAR_LOGIN},
221352488Sbrian  {"logout", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
221452488Sbrian  "logout script", "set logout chat-script", (const void *) VAR_LOGOUT},
221536285Sbrian  {"lqrperiod", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
221636285Sbrian  "LQR period", "set lqrperiod value", (const void *)VAR_LQRPERIOD},
221736285Sbrian  {"mode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "mode value",
221836285Sbrian  "set mode interactive|auto|ddial|background", (const void *)VAR_MODE},
221936285Sbrian  {"mrru", NULL, SetVariable, LOCAL_AUTH, "MRRU value",
222036285Sbrian  "set mrru value", (const void *)VAR_MRRU},
222136285Sbrian  {"mru", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
222278410Sbrian  "MRU value", "set mru [max[imum]] [value]", (const void *)VAR_MRU},
222378410Sbrian  {"mtu", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
222478410Sbrian  "interface MTU value", "set mtu [max[imum]] [value]", (const void *)VAR_MTU},
222536285Sbrian  {"nbns", NULL, SetVariable, LOCAL_AUTH, "NetBIOS Name Server",
222636285Sbrian  "set nbns pri-addr [sec-addr]", (const void *)VAR_NBNS},
222736285Sbrian  {"openmode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "open mode",
222836285Sbrian  "set openmode active|passive [secs]", (const void *)VAR_OPENMODE},
222944305Sbrian  {"papretry", "papretries", SetVariable, LOCAL_AUTH | LOCAL_CX, "PAP retries",
223044305Sbrian   "set papretry value [attempts]", (const void *)VAR_PAPRETRY},
223146686Sbrian  {"parity", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "serial parity",
223246686Sbrian   "set parity [odd|even|none]", (const void *)VAR_PARITY},
223336285Sbrian  {"phone", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "telephone number(s)",
223436285Sbrian  "set phone phone1[:phone2[...]]", (const void *)VAR_PHONE},
223540679Sbrian  {"proctitle", "title", SetProcTitle, LOCAL_AUTH,
223640679Sbrian  "Process title", "set proctitle [value]"},
223743313Sbrian#ifndef NORADIUS
223843313Sbrian  {"radius", NULL, SetVariable, LOCAL_AUTH,
223943313Sbrian  "RADIUS Config", "set radius cfgfile", (const void *)VAR_RADIUS},
224043313Sbrian#endif
224136285Sbrian  {"reconnect", NULL, datalink_SetReconnect, LOCAL_AUTH | LOCAL_CX,
224236285Sbrian  "Reconnect timeout", "set reconnect value ntries"},
224340665Sbrian  {"recvpipe", NULL, SetVariable, LOCAL_AUTH,
224440665Sbrian  "RECVPIPE value", "set recvpipe value", (const void *)VAR_RECVPIPE},
224536285Sbrian  {"redial", NULL, datalink_SetRedial, LOCAL_AUTH | LOCAL_CX,
224644468Sbrian  "Redial timeout", "set redial secs[+inc[-incmax]][.next] [attempts]"},
224740665Sbrian  {"sendpipe", NULL, SetVariable, LOCAL_AUTH,
224840665Sbrian  "SENDPIPE value", "set sendpipe value", (const void *)VAR_SENDPIPE},
224971657Sbrian  {"server", "socket", SetServer, LOCAL_AUTH, "diagnostic port",
225071657Sbrian  "set server|socket TcpPort|LocalName|none|open|closed [password [mask]]"},
225136285Sbrian  {"speed", NULL, SetModemSpeed, LOCAL_AUTH | LOCAL_CX,
225246686Sbrian  "physical speed", "set speed value|sync"},
225336285Sbrian  {"stopped", NULL, SetStoppedTimeout, LOCAL_AUTH | LOCAL_CX,
225436285Sbrian  "STOPPED timeouts", "set stopped [LCPseconds [CCPseconds]]"},
225536285Sbrian  {"timeout", NULL, SetVariable, LOCAL_AUTH, "Idle timeout",
225636285Sbrian  "set timeout idletime", (const void *)VAR_IDLETIMEOUT},
225751048Sbrian  {"urgent", NULL, SetVariable, LOCAL_AUTH, "urgent ports",
225851048Sbrian  "set urgent [tcp|udp] [+|-]port...", (const void *)VAR_URGENTPORTS},
225936285Sbrian  {"vj", NULL, ipcp_vjset, LOCAL_AUTH,
226036285Sbrian  "vj values", "set vj slots|slotcomp [value]"},
226128679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
226231343Sbrian  "Display this message", "set help|? [command]", SetCommands},
226328679Sbrian  {NULL, NULL, NULL},
22646059Samurai};
22656059Samurai
22666059Samuraistatic int
226731343SbrianSetCommand(struct cmdargs const *arg)
22686059Samurai{
226936285Sbrian  if (arg->argc > arg->argn)
227036285Sbrian    FindExec(arg->bundle, SetCommands, arg->argc, arg->argn, arg->argv,
227136285Sbrian             arg->prompt, arg->cx);
227236285Sbrian  else if (arg->prompt)
227336285Sbrian    prompt_Printf(arg->prompt, "Use `set ?' to get a list or `set ? <var>' for"
227458044Sbrian	          " syntax help.\n");
22756059Samurai  else
227636285Sbrian    log_Printf(LogWARN, "set command must have arguments\n");
227726516Sbrian
227826516Sbrian  return 0;
22796059Samurai}
22806059Samurai
22816059Samuraistatic int
228231343SbrianAddCommand(struct cmdargs const *arg)
22836059Samurai{
228481634Sbrian  struct ncpaddr gw;
228581634Sbrian  struct ncprange dest;
228681634Sbrian  struct in_addr host;
228781634Sbrian  int dest_default, gw_arg, addrs;
22886059Samurai
228936285Sbrian  if (arg->argc != arg->argn+3 && arg->argc != arg->argn+2)
229031598Sbrian    return -1;
229131598Sbrian
229236285Sbrian  addrs = 0;
229381634Sbrian  dest_default = 0;
229481634Sbrian  if (arg->argc == arg->argn + 2) {
229536285Sbrian    if (!strcasecmp(arg->argv[arg->argn], "default"))
229681634Sbrian      dest_default = 1;
229731598Sbrian    else {
229881634Sbrian      if (!ncprange_aton(&dest, &arg->bundle->ncp, arg->argv[arg->argn]))
229936285Sbrian        return -1;
230036285Sbrian      if (!strncasecmp(arg->argv[arg->argn], "MYADDR", 6))
230136285Sbrian        addrs = ROUTE_DSTMYADDR;
230281634Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "MYADDR6", 7))
230381634Sbrian        addrs = ROUTE_DSTMYADDR6;
230436285Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "HISADDR", 7))
230536285Sbrian        addrs = ROUTE_DSTHISADDR;
230681634Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "HISADDR6", 8))
230781634Sbrian        addrs = ROUTE_DSTHISADDR6;
230858044Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "DNS0", 4))
230958044Sbrian        addrs = ROUTE_DSTDNS0;
231058044Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "DNS1", 4))
231158044Sbrian        addrs = ROUTE_DSTDNS1;
231231598Sbrian    }
231381634Sbrian    gw_arg = 1;
231434536Sbrian  } else {
231536285Sbrian    if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
231636285Sbrian      addrs = ROUTE_DSTMYADDR;
231781634Sbrian      host = arg->bundle->ncp.ipcp.my_ip;
231836285Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
231936285Sbrian      addrs = ROUTE_DSTHISADDR;
232081634Sbrian      host = arg->bundle->ncp.ipcp.peer_ip;
232158044Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "DNS0") == 0) {
232258044Sbrian      addrs = ROUTE_DSTDNS0;
232381634Sbrian      host = arg->bundle->ncp.ipcp.ns.dns[0];
232458044Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "DNS1") == 0) {
232558044Sbrian      addrs = ROUTE_DSTDNS1;
232681634Sbrian      host = arg->bundle->ncp.ipcp.ns.dns[1];
232765263Sbrian    } else {
232881634Sbrian      host = GetIpAddr(arg->argv[arg->argn]);
232981634Sbrian      if (host.s_addr == INADDR_NONE) {
233065263Sbrian        log_Printf(LogWARN, "%s: Invalid destination address\n",
233165263Sbrian                   arg->argv[arg->argn]);
233265263Sbrian        return -1;
233365263Sbrian      }
233465263Sbrian    }
233581634Sbrian    ncprange_setip4(&dest, host, GetIpAddr(arg->argv[arg->argn + 1]));
233681634Sbrian    gw_arg = 2;
23376059Samurai  }
233836285Sbrian
233981634Sbrian  if (strcasecmp(arg->argv[arg->argn + gw_arg], "HISADDR") == 0) {
234081634Sbrian    ncpaddr_setip4(&gw, arg->bundle->ncp.ipcp.peer_ip);
234136285Sbrian    addrs |= ROUTE_GWHISADDR;
234281634Sbrian#ifndef NOINET6
234381634Sbrian  } else if (strcasecmp(arg->argv[arg->argn + gw_arg], "HISADDR6") == 0) {
234481634Sbrian    ncpaddr_copy(&gw, &arg->bundle->ncp.ipv6cp.hisaddr);
234581634Sbrian    addrs |= ROUTE_GWHISADDR6;
234681634Sbrian#endif
234765263Sbrian  } else {
234881634Sbrian    if (!ncpaddr_aton(&gw, &arg->bundle->ncp, arg->argv[arg->argn + gw_arg])) {
234965263Sbrian      log_Printf(LogWARN, "%s: Invalid gateway address\n",
235081634Sbrian                 arg->argv[arg->argn + gw_arg]);
235165263Sbrian      return -1;
235265263Sbrian    }
235365263Sbrian  }
235436285Sbrian
235581634Sbrian  if (dest_default)
235681634Sbrian    ncprange_setdefault(&dest, ncpaddr_family(&gw));
235781634Sbrian
235881634Sbrian  if (rt_Set(arg->bundle, RTM_ADD, &dest, &gw, arg->cmd->args ? 1 : 0,
235981634Sbrian             ((addrs & ROUTE_GWHISADDR) || (addrs & ROUTE_GWHISADDR6)) ? 1 : 0)
236043313Sbrian      && addrs != ROUTE_STATIC)
236181634Sbrian    route_Add(&arg->bundle->ncp.route, addrs, &dest, &gw);
236236285Sbrian
236331598Sbrian  return 0;
23646059Samurai}
23656059Samurai
23666059Samuraistatic int
236731343SbrianDeleteCommand(struct cmdargs const *arg)
23686059Samurai{
236981634Sbrian  struct ncprange dest;
237036285Sbrian  int addrs;
23716059Samurai
237236285Sbrian  if (arg->argc == arg->argn+1) {
237336285Sbrian    if(strcasecmp(arg->argv[arg->argn], "all") == 0) {
237436285Sbrian      route_IfDelete(arg->bundle, 0);
237581634Sbrian      route_DeleteAll(&arg->bundle->ncp.route);
237636285Sbrian    } else {
237736285Sbrian      addrs = 0;
237836285Sbrian      if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
237981634Sbrian        ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.my_ip);
238036285Sbrian        addrs = ROUTE_DSTMYADDR;
238181634Sbrian#ifndef NOINET6
238281634Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "MYADDR6") == 0) {
238381634Sbrian        ncprange_sethost(&dest, &arg->bundle->ncp.ipv6cp.myaddr);
238481634Sbrian        addrs = ROUTE_DSTMYADDR6;
238581634Sbrian#endif
238636285Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
238781634Sbrian        ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.peer_ip);
238836285Sbrian        addrs = ROUTE_DSTHISADDR;
238981634Sbrian#ifndef NOINET6
239081634Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "HISADDR6") == 0) {
239181634Sbrian        ncprange_sethost(&dest, &arg->bundle->ncp.ipv6cp.hisaddr);
239281634Sbrian        addrs = ROUTE_DSTHISADDR6;
239381634Sbrian#endif
239458044Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "DNS0") == 0) {
239581634Sbrian        ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.ns.dns[0]);
239658044Sbrian        addrs = ROUTE_DSTDNS0;
239758044Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "DNS1") == 0) {
239881634Sbrian        ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.ns.dns[1]);
239958044Sbrian        addrs = ROUTE_DSTDNS1;
240036285Sbrian      } else {
240181634Sbrian        ncprange_aton(&dest, &arg->bundle->ncp, arg->argv[arg->argn]);
240236285Sbrian        addrs = ROUTE_STATIC;
240336285Sbrian      }
240481634Sbrian      rt_Set(arg->bundle, RTM_DELETE, &dest, NULL, arg->cmd->args ? 1 : 0, 0);
240581634Sbrian      route_Delete(&arg->bundle->ncp.route, addrs, &dest);
240631598Sbrian    }
240734536Sbrian  } else
240826516Sbrian    return -1;
240926516Sbrian
241026516Sbrian  return 0;
24116059Samurai}
24126059Samurai
241350059Sbrian#ifndef NONAT
241426031Sbrianstatic int
241558867SbrianNatEnable(struct cmdargs const *arg)
241626031Sbrian{
241736285Sbrian  if (arg->argc == arg->argn+1) {
241836285Sbrian    if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
241950059Sbrian      if (!arg->bundle->NatEnabled) {
242046686Sbrian        if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED)
242146686Sbrian          PacketAliasSetAddress(arg->bundle->ncp.ipcp.my_ip);
242250059Sbrian        arg->bundle->NatEnabled = 1;
242346686Sbrian      }
242437191Sbrian      return 0;
242536285Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "no") == 0) {
242650059Sbrian      arg->bundle->NatEnabled = 0;
242740561Sbrian      arg->bundle->cfg.opt &= ~OPT_IFACEALIAS;
242840561Sbrian      /* Don't iface_Clear() - there may be manually configured addresses */
242926516Sbrian      return 0;
243026142Sbrian    }
243135449Sbrian  }
243236285Sbrian
243326516Sbrian  return -1;
243426031Sbrian}
243526031Sbrian
243626031Sbrian
243726031Sbrianstatic int
243858867SbrianNatOption(struct cmdargs const *arg)
243926031Sbrian{
244038559Sbrian  long param = (long)arg->cmd->args;
244138559Sbrian
244236285Sbrian  if (arg->argc == arg->argn+1) {
244336285Sbrian    if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
244450059Sbrian      if (arg->bundle->NatEnabled) {
244537191Sbrian	PacketAliasSetMode(param, param);
244628679Sbrian	return 0;
244728679Sbrian      }
244850059Sbrian      log_Printf(LogWARN, "nat not enabled\n");
244936285Sbrian    } else if (strcmp(arg->argv[arg->argn], "no") == 0) {
245050059Sbrian      if (arg->bundle->NatEnabled) {
245137191Sbrian	PacketAliasSetMode(0, param);
245228679Sbrian	return 0;
245328679Sbrian      }
245450059Sbrian      log_Printf(LogWARN, "nat not enabled\n");
245528679Sbrian    }
245635449Sbrian  }
245728679Sbrian  return -1;
245826031Sbrian}
245950059Sbrian#endif /* #ifndef NONAT */
246031121Sbrian
246131121Sbrianstatic int
246236285SbrianLinkCommand(struct cmdargs const *arg)
246336285Sbrian{
246436285Sbrian  if (arg->argc > arg->argn+1) {
246536285Sbrian    char namelist[LINE_LEN];
246636285Sbrian    struct datalink *cx;
246736285Sbrian    char *name;
246836285Sbrian    int result = 0;
246936285Sbrian
247036285Sbrian    if (!strcmp(arg->argv[arg->argn], "*")) {
247136285Sbrian      struct datalink *dl;
247236285Sbrian
247336285Sbrian      cx = arg->bundle->links;
247436285Sbrian      while (cx) {
247536285Sbrian        /* Watch it, the command could be a ``remove'' */
247636285Sbrian        dl = cx->next;
247736285Sbrian        FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
247836285Sbrian                 arg->prompt, cx);
247936285Sbrian        for (cx = arg->bundle->links; cx; cx = cx->next)
248036285Sbrian          if (cx == dl)
248136285Sbrian            break;		/* Pointer's still valid ! */
248236285Sbrian      }
248336285Sbrian    } else {
248436285Sbrian      strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
248536285Sbrian      namelist[sizeof namelist - 1] = '\0';
248636285Sbrian      for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
248736285Sbrian        if (!bundle2datalink(arg->bundle, name)) {
248836285Sbrian          log_Printf(LogWARN, "link: %s: Invalid link name\n", name);
248936285Sbrian          return 1;
249036285Sbrian        }
249136285Sbrian
249236285Sbrian      strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
249336285Sbrian      namelist[sizeof namelist - 1] = '\0';
249436285Sbrian      for(name = strtok(namelist, ", "); name; name = strtok(NULL,", ")) {
249536285Sbrian        cx = bundle2datalink(arg->bundle, name);
249636285Sbrian        if (cx)
249736285Sbrian          FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
249836285Sbrian                   arg->prompt, cx);
249936285Sbrian        else {
250036285Sbrian          log_Printf(LogWARN, "link: %s: Invalidated link name !\n", name);
250136285Sbrian          result++;
250236285Sbrian        }
250336285Sbrian      }
250436285Sbrian    }
250536285Sbrian    return result;
250636285Sbrian  }
250736285Sbrian
250836285Sbrian  log_Printf(LogWARN, "Usage: %s\n", arg->cmd->syntax);
250936285Sbrian  return 2;
251036285Sbrian}
251136285Sbrian
251236285Sbrianstruct link *
251336285Sbriancommand_ChooseLink(struct cmdargs const *arg)
251436285Sbrian{
251536285Sbrian  if (arg->cx)
251636285Sbrian    return &arg->cx->physical->link;
251737210Sbrian  else if (!arg->bundle->ncp.mp.cfg.mrru) {
251836285Sbrian    struct datalink *dl = bundle2datalink(arg->bundle, NULL);
251937210Sbrian    if (dl)
252037210Sbrian      return &dl->physical->link;
252136285Sbrian  }
252237210Sbrian  return &arg->bundle->ncp.mp.link;
252336285Sbrian}
252436285Sbrian
252536285Sbrianstatic const char *
252636285Sbrianident_cmd(const char *cmd, unsigned *keep, unsigned *add)
252736285Sbrian{
252836285Sbrian  const char *result;
252936285Sbrian
253036285Sbrian  switch (*cmd) {
253136285Sbrian    case 'A':
253236285Sbrian    case 'a':
253336285Sbrian      result = "accept";
253436285Sbrian      *keep = NEG_MYMASK;
253536285Sbrian      *add = NEG_ACCEPTED;
253636285Sbrian      break;
253736285Sbrian    case 'D':
253836285Sbrian    case 'd':
253936285Sbrian      switch (cmd[1]) {
254036285Sbrian        case 'E':
254136285Sbrian        case 'e':
254236285Sbrian          result = "deny";
254336285Sbrian          *keep = NEG_MYMASK;
254436285Sbrian          *add = 0;
254536285Sbrian          break;
254636285Sbrian        case 'I':
254736285Sbrian        case 'i':
254836285Sbrian          result = "disable";
254936285Sbrian          *keep = NEG_HISMASK;
255036285Sbrian          *add = 0;
255136285Sbrian          break;
255236285Sbrian        default:
255336285Sbrian          return NULL;
255436285Sbrian      }
255536285Sbrian      break;
255636285Sbrian    case 'E':
255736285Sbrian    case 'e':
255836285Sbrian      result = "enable";
255936285Sbrian      *keep = NEG_HISMASK;
256036285Sbrian      *add = NEG_ENABLED;
256136285Sbrian      break;
256236285Sbrian    default:
256336285Sbrian      return NULL;
256436285Sbrian  }
256536285Sbrian
256636285Sbrian  return result;
256736285Sbrian}
256836285Sbrian
256936285Sbrianstatic int
257036285SbrianOptSet(struct cmdargs const *arg)
257136285Sbrian{
257237574Sbrian  int bit = (int)(long)arg->cmd->args;
257336285Sbrian  const char *cmd;
257436285Sbrian  unsigned keep;			/* Keep these bits */
257536285Sbrian  unsigned add;				/* Add these bits */
257636285Sbrian
257781697Sbrian  if (ident_cmd(arg->argv[arg->argn - 2], &keep, &add) == NULL)
257836285Sbrian    return 1;
257936285Sbrian
258081697Sbrian  if (add == NEG_ENABLED && bit == OPT_IPV6CP && !probe.ipv6_available) {
258181697Sbrian    log_Printf(LogWARN, "IPv6 is not available on this machine\n");
258281697Sbrian    return 1;
258381697Sbrian  }
258481697Sbrian
258536285Sbrian  if (add)
258636285Sbrian    arg->bundle->cfg.opt |= bit;
258736285Sbrian  else
258836285Sbrian    arg->bundle->cfg.opt &= ~bit;
258981697Sbrian
259036285Sbrian  return 0;
259136285Sbrian}
259236285Sbrian
259336285Sbrianstatic int
259440561SbrianIfaceAliasOptSet(struct cmdargs const *arg)
259540561Sbrian{
259640561Sbrian  unsigned save = arg->bundle->cfg.opt;
259740561Sbrian  int result = OptSet(arg);
259840561Sbrian
259940561Sbrian  if (result == 0)
260050059Sbrian    if (Enabled(arg->bundle, OPT_IFACEALIAS) && !arg->bundle->NatEnabled) {
260140561Sbrian      arg->bundle->cfg.opt = save;
260250059Sbrian      log_Printf(LogWARN, "Cannot enable iface-alias without NAT\n");
260340561Sbrian      result = 2;
260440561Sbrian    }
260540561Sbrian
260640561Sbrian  return result;
260740561Sbrian}
260840561Sbrian
260940561Sbrianstatic int
261036285SbrianNegotiateSet(struct cmdargs const *arg)
261136285Sbrian{
261237210Sbrian  long param = (long)arg->cmd->args;
261336285Sbrian  struct link *l = command_ChooseLink(arg);	/* LOCAL_CX_OPT uses this */
261436285Sbrian  struct datalink *cx = arg->cx;	/* LOCAL_CX uses this */
261536285Sbrian  const char *cmd;
261636285Sbrian  unsigned keep;			/* Keep these bits */
261736285Sbrian  unsigned add;				/* Add these bits */
261836285Sbrian
261936285Sbrian  if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL)
262036285Sbrian    return 1;
262136285Sbrian
262236285Sbrian  if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
262336285Sbrian    log_Printf(LogWARN, "%s %s: No context (use the `link' command)\n",
262436285Sbrian              cmd, arg->cmd->name);
262536285Sbrian    return 2;
262636285Sbrian  } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
262736285Sbrian    log_Printf(LogWARN, "%s %s: Redundant context (%s) ignored\n",
262836285Sbrian              cmd, arg->cmd->name, cx->name);
262936285Sbrian    cx = NULL;
263036285Sbrian  }
263136285Sbrian
263236285Sbrian  switch (param) {
263336285Sbrian    case NEG_ACFCOMP:
263436285Sbrian      cx->physical->link.lcp.cfg.acfcomp &= keep;
263536285Sbrian      cx->physical->link.lcp.cfg.acfcomp |= add;
263636285Sbrian      break;
263744106Sbrian    case NEG_CHAP05:
263844106Sbrian      cx->physical->link.lcp.cfg.chap05 &= keep;
263944106Sbrian      cx->physical->link.lcp.cfg.chap05 |= add;
264036285Sbrian      break;
264144106Sbrian#ifdef HAVE_DES
264244106Sbrian    case NEG_CHAP80:
264344106Sbrian      cx->physical->link.lcp.cfg.chap80nt &= keep;
264444106Sbrian      cx->physical->link.lcp.cfg.chap80nt |= add;
264544106Sbrian      break;
264644106Sbrian    case NEG_CHAP80LM:
264744106Sbrian      cx->physical->link.lcp.cfg.chap80lm &= keep;
264844106Sbrian      cx->physical->link.lcp.cfg.chap80lm |= add;
264944106Sbrian      break;
265067910Sbrian    case NEG_CHAP81:
265167910Sbrian      cx->physical->link.lcp.cfg.chap81 &= keep;
265267910Sbrian      cx->physical->link.lcp.cfg.chap81 |= add;
265367910Sbrian      break;
265467910Sbrian    case NEG_MPPE:
265567910Sbrian      l->ccp.cfg.neg[CCP_NEG_MPPE] &= keep;
265667910Sbrian      l->ccp.cfg.neg[CCP_NEG_MPPE] |= add;
265767910Sbrian      break;
265844106Sbrian#endif
265936285Sbrian    case NEG_DEFLATE:
266036285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE] &= keep;
266136285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE] |= add;
266236285Sbrian      break;
266336285Sbrian    case NEG_DNS:
266436285Sbrian      arg->bundle->ncp.ipcp.cfg.ns.dns_neg &= keep;
266536285Sbrian      arg->bundle->ncp.ipcp.cfg.ns.dns_neg |= add;
266636285Sbrian      break;
266747858Sbrian    case NEG_ENDDISC:
266847858Sbrian      arg->bundle->ncp.mp.cfg.negenddisc &= keep;
266947858Sbrian      arg->bundle->ncp.mp.cfg.negenddisc |= add;
267047858Sbrian      break;
267136285Sbrian    case NEG_LQR:
267236285Sbrian      cx->physical->link.lcp.cfg.lqr &= keep;
267336285Sbrian      cx->physical->link.lcp.cfg.lqr |= add;
267436285Sbrian      break;
267536285Sbrian    case NEG_PAP:
267636285Sbrian      cx->physical->link.lcp.cfg.pap &= keep;
267736285Sbrian      cx->physical->link.lcp.cfg.pap |= add;
267836285Sbrian      break;
267936285Sbrian    case NEG_PPPDDEFLATE:
268036285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE24] &= keep;
268136285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE24] |= add;
268236285Sbrian      break;
268336285Sbrian    case NEG_PRED1:
268436285Sbrian      l->ccp.cfg.neg[CCP_NEG_PRED1] &= keep;
268536285Sbrian      l->ccp.cfg.neg[CCP_NEG_PRED1] |= add;
268636285Sbrian      break;
268736285Sbrian    case NEG_PROTOCOMP:
268836285Sbrian      cx->physical->link.lcp.cfg.protocomp &= keep;
268936285Sbrian      cx->physical->link.lcp.cfg.protocomp |= add;
269036285Sbrian      break;
269136285Sbrian    case NEG_SHORTSEQ:
269240622Sbrian      switch (bundle_Phase(arg->bundle)) {
269340622Sbrian        case PHASE_DEAD:
269440622Sbrian          break;
269540622Sbrian        case PHASE_ESTABLISH:
269640622Sbrian          /* Make sure none of our links are DATALINK_LCP or greater */
269740622Sbrian          if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) {
269840622Sbrian            log_Printf(LogWARN, "shortseq: Only changable before"
269940622Sbrian                       " LCP negotiations\n");
270040622Sbrian            return 1;
270140622Sbrian          }
270240622Sbrian          break;
270340622Sbrian        default:
270440622Sbrian          log_Printf(LogWARN, "shortseq: Only changable at phase"
270540622Sbrian                     " DEAD/ESTABLISH\n");
270640622Sbrian          return 1;
270736285Sbrian      }
270840622Sbrian      arg->bundle->ncp.mp.cfg.shortseq &= keep;
270940622Sbrian      arg->bundle->ncp.mp.cfg.shortseq |= add;
271036285Sbrian      break;
271136285Sbrian    case NEG_VJCOMP:
271236285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.neg &= keep;
271336285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.neg |= add;
271436285Sbrian      break;
271536285Sbrian  }
271636285Sbrian
271736285Sbrian  return 0;
271836285Sbrian}
271936285Sbrian
272036285Sbrianstatic struct cmdtab const NegotiateCommands[] = {
272162778Sbrian  {"filter-decapsulation", NULL, OptSet, LOCAL_AUTH,
272262778Sbrian  "filter on PPPoUDP payloads", "disable|enable",
272362778Sbrian  (const void *)OPT_FILTERDECAP},
272436285Sbrian  {"idcheck", NULL, OptSet, LOCAL_AUTH, "Check FSM reply ids",
272536285Sbrian  "disable|enable", (const void *)OPT_IDCHECK},
272640666Sbrian  {"iface-alias", NULL, IfaceAliasOptSet, LOCAL_AUTH,
272762778Sbrian  "retain interface addresses", "disable|enable",
272862778Sbrian  (const void *)OPT_IFACEALIAS},
272981634Sbrian#ifndef NOINET6
273081634Sbrian  {"ipcp", NULL, OptSet, LOCAL_AUTH, "IP Network Control Protocol",
273181634Sbrian  "disable|enable", (const void *)OPT_IPCP},
273281634Sbrian  {"ipv6cp", NULL, OptSet, LOCAL_AUTH, "IPv6 Network Control Protocol",
273381634Sbrian  "disable|enable", (const void *)OPT_IPV6CP},
273481634Sbrian#endif
273547689Sbrian  {"keep-session", NULL, OptSet, LOCAL_AUTH, "Retain device session leader",
273647689Sbrian  "disable|enable", (const void *)OPT_KEEPSESSION},
273736285Sbrian  {"loopback", NULL, OptSet, LOCAL_AUTH, "Loop packets for local iface",
273836285Sbrian  "disable|enable", (const void *)OPT_LOOPBACK},
273936285Sbrian  {"passwdauth", NULL, OptSet, LOCAL_AUTH, "Use passwd file",
274036285Sbrian  "disable|enable", (const void *)OPT_PASSWDAUTH},
274140665Sbrian  {"proxy", NULL, OptSet, LOCAL_AUTH, "Create a proxy ARP entry",
274236285Sbrian  "disable|enable", (const void *)OPT_PROXY},
274340665Sbrian  {"proxyall", NULL, OptSet, LOCAL_AUTH, "Proxy ARP for all remote hosts",
274440665Sbrian  "disable|enable", (const void *)OPT_PROXYALL},
274536285Sbrian  {"sroutes", NULL, OptSet, LOCAL_AUTH, "Use sticky routes",
274636285Sbrian  "disable|enable", (const void *)OPT_SROUTES},
274769303Sbrian  {"tcpmssfixup", "mssfixup", OptSet, LOCAL_AUTH, "Modify MSS options",
274869303Sbrian  "disable|enable", (const void *)OPT_TCPMSSFIXUP},
274936285Sbrian  {"throughput", NULL, OptSet, LOCAL_AUTH, "Rolling throughput",
275036285Sbrian  "disable|enable", (const void *)OPT_THROUGHPUT},
275136285Sbrian  {"utmp", NULL, OptSet, LOCAL_AUTH, "Log connections in utmp",
275236285Sbrian  "disable|enable", (const void *)OPT_UTMP},
275336285Sbrian
275481634Sbrian#ifndef NOINET6
275581634Sbrian#define OPT_MAX 13	/* accept/deny allowed below and not above */
275681634Sbrian#else
275781634Sbrian#define OPT_MAX 11
275881634Sbrian#endif
275936285Sbrian
276036285Sbrian  {"acfcomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
276136285Sbrian  "Address & Control field compression", "accept|deny|disable|enable",
276236285Sbrian  (const void *)NEG_ACFCOMP},
276344106Sbrian  {"chap", "chap05", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
276436285Sbrian  "Challenge Handshake Authentication Protocol", "accept|deny|disable|enable",
276544106Sbrian  (const void *)NEG_CHAP05},
276644106Sbrian#ifdef HAVE_DES
276744106Sbrian  {"mschap", "chap80nt", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
276844106Sbrian  "Microsoft (NT) CHAP", "accept|deny|disable|enable",
276944106Sbrian  (const void *)NEG_CHAP80},
277044106Sbrian  {"LANMan", "chap80lm", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
277144106Sbrian  "Microsoft (NT) CHAP", "accept|deny|disable|enable",
277244106Sbrian  (const void *)NEG_CHAP80LM},
277367910Sbrian  {"mschapv2", "chap81", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
277467910Sbrian  "Microsoft CHAP v2", "accept|deny|disable|enable",
277567910Sbrian  (const void *)NEG_CHAP81},
277667910Sbrian  {"mppe", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
277767910Sbrian  "MPPE encryption", "accept|deny|disable|enable",
277867910Sbrian  (const void *)NEG_MPPE},
277944106Sbrian#endif
278036285Sbrian  {"deflate", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
278136285Sbrian  "Deflate compression", "accept|deny|disable|enable",
278236285Sbrian  (const void *)NEG_DEFLATE},
278336285Sbrian  {"deflate24", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
278436285Sbrian  "Deflate (type 24) compression", "accept|deny|disable|enable",
278536285Sbrian  (const void *)NEG_PPPDDEFLATE},
278636285Sbrian  {"dns", NULL, NegotiateSet, LOCAL_AUTH,
278736285Sbrian  "DNS specification", "accept|deny|disable|enable", (const void *)NEG_DNS},
278847858Sbrian  {"enddisc", NULL, NegotiateSet, LOCAL_AUTH, "ENDDISC negotiation",
278947858Sbrian  "accept|deny|disable|enable", (const void *)NEG_ENDDISC},
279036285Sbrian  {"lqr", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
279136285Sbrian  "Link Quality Reports", "accept|deny|disable|enable",
279236285Sbrian  (const void *)NEG_LQR},
279336285Sbrian  {"pap", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
279436285Sbrian  "Password Authentication protocol", "accept|deny|disable|enable",
279536285Sbrian  (const void *)NEG_PAP},
279636285Sbrian  {"pred1", "predictor1", NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
279736285Sbrian  "Predictor 1 compression", "accept|deny|disable|enable",
279836285Sbrian  (const void *)NEG_PRED1},
279936285Sbrian  {"protocomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
280036285Sbrian  "Protocol field compression", "accept|deny|disable|enable",
280136285Sbrian  (const void *)NEG_PROTOCOMP},
280236285Sbrian  {"shortseq", NULL, NegotiateSet, LOCAL_AUTH,
280336285Sbrian  "MP Short Sequence Numbers", "accept|deny|disable|enable",
280436285Sbrian  (const void *)NEG_SHORTSEQ},
280536285Sbrian  {"vjcomp", NULL, NegotiateSet, LOCAL_AUTH,
280636285Sbrian  "Van Jacobson header compression", "accept|deny|disable|enable",
280736285Sbrian  (const void *)NEG_VJCOMP},
280836285Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
280936285Sbrian  "Display this message", "accept|deny|disable|enable help|? [value]",
281036285Sbrian  NegotiateCommands},
281136285Sbrian  {NULL, NULL, NULL},
281236285Sbrian};
281336285Sbrian
281436285Sbrianstatic int
281536285SbrianNegotiateCommand(struct cmdargs const *arg)
281636285Sbrian{
281736285Sbrian  if (arg->argc > arg->argn) {
281836285Sbrian    char const *argv[3];
281936285Sbrian    unsigned keep, add;
282036285Sbrian    int n;
282136285Sbrian
282236285Sbrian    if ((argv[0] = ident_cmd(arg->argv[arg->argn-1], &keep, &add)) == NULL)
282336285Sbrian      return -1;
282436285Sbrian    argv[2] = NULL;
282536285Sbrian
282636285Sbrian    for (n = arg->argn; n < arg->argc; n++) {
282736285Sbrian      argv[1] = arg->argv[n];
282836285Sbrian      FindExec(arg->bundle, NegotiateCommands + (keep == NEG_HISMASK ?
282936285Sbrian               0 : OPT_MAX), 2, 1, argv, arg->prompt, arg->cx);
283036285Sbrian    }
283136285Sbrian  } else if (arg->prompt)
283236285Sbrian    prompt_Printf(arg->prompt, "Use `%s ?' to get a list.\n",
283336285Sbrian	    arg->argv[arg->argn-1]);
283436285Sbrian  else
283536285Sbrian    log_Printf(LogWARN, "%s command must have arguments\n",
283636285Sbrian              arg->argv[arg->argn] );
283736285Sbrian
283836285Sbrian  return 0;
283936285Sbrian}
284036285Sbrian
284136285Sbrianconst char *
284236285Sbriancommand_ShowNegval(unsigned val)
284336285Sbrian{
284436285Sbrian  switch (val&3) {
284536285Sbrian    case 1: return "disabled & accepted";
284636285Sbrian    case 2: return "enabled & denied";
284736285Sbrian    case 3: return "enabled & accepted";
284836285Sbrian  }
284936285Sbrian  return "disabled & denied";
285036285Sbrian}
285136934Sbrian
285236934Sbrianstatic int
285336934SbrianClearCommand(struct cmdargs const *arg)
285436934Sbrian{
285536934Sbrian  struct pppThroughput *t;
285636934Sbrian  struct datalink *cx;
285736934Sbrian  int i, clear_type;
285836934Sbrian
285936934Sbrian  if (arg->argc < arg->argn + 1)
286036934Sbrian    return -1;
286136934Sbrian
286246686Sbrian  if (strcasecmp(arg->argv[arg->argn], "physical") == 0) {
286336934Sbrian    cx = arg->cx;
286436934Sbrian    if (!cx)
286536934Sbrian      cx = bundle2datalink(arg->bundle, NULL);
286636934Sbrian    if (!cx) {
286746686Sbrian      log_Printf(LogWARN, "A link must be specified for ``clear physical''\n");
286836934Sbrian      return 1;
286936934Sbrian    }
287064652Sbrian    t = &cx->physical->link.stats.total;
287136934Sbrian  } else if (strcasecmp(arg->argv[arg->argn], "ipcp") == 0)
287236934Sbrian    t = &arg->bundle->ncp.ipcp.throughput;
287381634Sbrian#ifndef NOINET6
287481634Sbrian  else if (strcasecmp(arg->argv[arg->argn], "ipv6cp") == 0)
287581634Sbrian    t = &arg->bundle->ncp.ipv6cp.throughput;
287681634Sbrian#endif
287736934Sbrian  else
287836934Sbrian    return -1;
287936934Sbrian
288036934Sbrian  if (arg->argc > arg->argn + 1) {
288136934Sbrian    clear_type = 0;
288236934Sbrian    for (i = arg->argn + 1; i < arg->argc; i++)
288336934Sbrian      if (strcasecmp(arg->argv[i], "overall") == 0)
288436934Sbrian        clear_type |= THROUGHPUT_OVERALL;
288536934Sbrian      else if (strcasecmp(arg->argv[i], "current") == 0)
288636934Sbrian        clear_type |= THROUGHPUT_CURRENT;
288736934Sbrian      else if (strcasecmp(arg->argv[i], "peak") == 0)
288836934Sbrian        clear_type |= THROUGHPUT_PEAK;
288936934Sbrian      else
289036934Sbrian        return -1;
289136934Sbrian  } else
289236934Sbrian    clear_type = THROUGHPUT_ALL;
289336934Sbrian
289436934Sbrian  throughput_clear(t, clear_type, arg->prompt);
289536934Sbrian  return 0;
289636934Sbrian}
289740561Sbrian
289840561Sbrianstatic int
289940561SbrianRunListCommand(struct cmdargs const *arg)
290040561Sbrian{
290140561Sbrian  const char *cmd = arg->argc ? arg->argv[arg->argc - 1] : "???";
290240561Sbrian
290364801Sbrian#ifndef NONAT
290464801Sbrian  if (arg->cmd->args == NatCommands &&
290564801Sbrian      tolower(*arg->argv[arg->argn - 1]) == 'a') {
290664801Sbrian    if (arg->prompt)
290765550Sbrian      prompt_Printf(arg->prompt, "The alias command is deprecated\n");
290864801Sbrian    else
290965550Sbrian      log_Printf(LogWARN, "The alias command is deprecated\n");
291064801Sbrian  }
291164801Sbrian#endif
291264801Sbrian
291340561Sbrian  if (arg->argc > arg->argn)
291440561Sbrian    FindExec(arg->bundle, arg->cmd->args, arg->argc, arg->argn, arg->argv,
291540561Sbrian             arg->prompt, arg->cx);
291640561Sbrian  else if (arg->prompt)
291740561Sbrian    prompt_Printf(arg->prompt, "Use `%s help' to get a list or `%s help"
291840561Sbrian                  " <option>' for syntax help.\n", cmd, cmd);
291940561Sbrian  else
292040561Sbrian    log_Printf(LogWARN, "%s command must have arguments\n", cmd);
292140561Sbrian
292240561Sbrian  return 0;
292340561Sbrian}
292440561Sbrian
292540561Sbrianstatic int
292640561SbrianIfaceAddCommand(struct cmdargs const *arg)
292740561Sbrian{
292881634Sbrian  struct ncpaddr peer, addr;
292981634Sbrian  struct ncprange ifa;
293081634Sbrian  struct in_addr mask;
293181634Sbrian  int n, how;
293240561Sbrian
293340664Sbrian  if (arg->argc == arg->argn + 1) {
293481634Sbrian    if (!ncprange_aton(&ifa, NULL, arg->argv[arg->argn]))
293540561Sbrian      return -1;
293681634Sbrian    ncpaddr_init(&peer);
293740664Sbrian  } else {
293840664Sbrian    if (arg->argc == arg->argn + 2) {
293981634Sbrian      if (!ncprange_aton(&ifa, NULL, arg->argv[arg->argn]))
294040664Sbrian        return -1;
294140664Sbrian      n = 1;
294240664Sbrian    } else if (arg->argc == arg->argn + 3) {
294381634Sbrian      if (!ncpaddr_aton(&addr, NULL, arg->argv[arg->argn]))
294440664Sbrian        return -1;
294581634Sbrian      if (ncpaddr_family(&addr) != AF_INET)
294640664Sbrian        return -1;
294781634Sbrian      ncprange_sethost(&ifa, &addr);
294881634Sbrian      if (!ncpaddr_aton(&addr, NULL, arg->argv[arg->argn + 1]))
294981634Sbrian        return -1;
295081634Sbrian      if (!ncpaddr_getip4(&addr, &mask))
295181634Sbrian        return -1;
295281634Sbrian      if (!ncprange_setip4mask(&ifa, mask))
295381634Sbrian        return -1;
295440664Sbrian      n = 2;
295540664Sbrian    } else
295640561Sbrian      return -1;
295740561Sbrian
295881634Sbrian    if (!ncpaddr_aton(&peer, NULL, arg->argv[arg->argn + n]))
295940664Sbrian      return -1;
296081634Sbrian
296181634Sbrian    if (ncprange_family(&ifa) != ncpaddr_family(&peer)) {
296281634Sbrian      log_Printf(LogWARN, "IfaceAddCommand: src and dst address families"
296381634Sbrian                 " differ\n");
296481634Sbrian      return -1;
296581634Sbrian    }
296640664Sbrian  }
296740561Sbrian
296840561Sbrian  how = IFACE_ADD_LAST;
296940561Sbrian  if (arg->cmd->args)
297040561Sbrian    how |= IFACE_FORCE_ADD;
297140561Sbrian
297281634Sbrian  return !iface_Add(arg->bundle->iface, &arg->bundle->ncp, &ifa, &peer, how);
297340561Sbrian}
297440561Sbrian
297540561Sbrianstatic int
297640561SbrianIfaceDeleteCommand(struct cmdargs const *arg)
297740561Sbrian{
297881634Sbrian  struct ncpaddr ifa;
297981634Sbrian  struct in_addr ifa4;
298040561Sbrian  int ok;
298140561Sbrian
298240561Sbrian  if (arg->argc != arg->argn + 1)
298340561Sbrian    return -1;
298440561Sbrian
298581634Sbrian  if (!ncpaddr_aton(&ifa, NULL, arg->argv[arg->argn]))
298640561Sbrian    return -1;
298740561Sbrian
298840561Sbrian  if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED &&
298981634Sbrian      ncpaddr_getip4(&ifa, &ifa4) &&
299081634Sbrian      arg->bundle->ncp.ipcp.my_ip.s_addr == ifa4.s_addr) {
299140561Sbrian    log_Printf(LogWARN, "%s: Cannot remove active interface address\n",
299281634Sbrian               ncpaddr_ntoa(&ifa));
299340561Sbrian    return 1;
299440561Sbrian  }
299540561Sbrian
299681634Sbrian  ok = iface_Delete(arg->bundle->iface, &arg->bundle->ncp, &ifa);
299740561Sbrian  if (!ok) {
299840561Sbrian    if (arg->cmd->args)
299940561Sbrian      ok = 1;
300040561Sbrian    else if (arg->prompt)
300181634Sbrian      prompt_Printf(arg->prompt, "%s: No such interface address\n",
300281634Sbrian                    ncpaddr_ntoa(&ifa));
300340561Sbrian    else
300481634Sbrian      log_Printf(LogWARN, "%s: No such interface address\n",
300581634Sbrian                 ncpaddr_ntoa(&ifa));
300640561Sbrian  }
300740561Sbrian
300840561Sbrian  return !ok;
300940561Sbrian}
301040561Sbrian
301140561Sbrianstatic int
301240561SbrianIfaceClearCommand(struct cmdargs const *arg)
301340561Sbrian{
301481634Sbrian  int family, how;
301540561Sbrian
301681634Sbrian  family = 0;
301781634Sbrian  if (arg->argc == arg->argn + 1) {
301881634Sbrian    if (strcasecmp(arg->argv[arg->argn], "inet") == 0)
301981634Sbrian      family = AF_INET;
302081634Sbrian#ifndef NOINET6
302181634Sbrian    else if (strcasecmp(arg->argv[arg->argn], "inet6") == 0)
302281634Sbrian      family = AF_INET6;
302381634Sbrian#endif
302481634Sbrian    else
302581634Sbrian      return -1;
302681634Sbrian  } else if (arg->argc != arg->argn)
302740561Sbrian    return -1;
302840561Sbrian
302940941Sbrian  how = arg->bundle->ncp.ipcp.fsm.state == ST_OPENED ||
303040941Sbrian        arg->bundle->phys_type.all & PHYS_AUTO ?
303140561Sbrian        IFACE_CLEAR_ALIASES : IFACE_CLEAR_ALL;
303281634Sbrian  iface_Clear(arg->bundle->iface, &arg->bundle->ncp, family, how);
303340561Sbrian
303440561Sbrian  return 0;
303540561Sbrian}
303640679Sbrian
303740679Sbrianstatic int
303840679SbrianSetProcTitle(struct cmdargs const *arg)
303940679Sbrian{
304040679Sbrian  static char title[LINE_LEN];
304140679Sbrian  char *argv[MAXARGS], *ptr;
304240679Sbrian  int len, remaining, f, argc = arg->argc - arg->argn;
304340679Sbrian
304440679Sbrian  if (arg->argc == arg->argn) {
304564698Sbrian    SetTitle(NULL);
304640679Sbrian    return 0;
304740679Sbrian  }
304840679Sbrian
304940679Sbrian  if (argc >= sizeof argv / sizeof argv[0]) {
305040679Sbrian    argc = sizeof argv / sizeof argv[0] - 1;
305140679Sbrian    log_Printf(LogWARN, "Truncating proc title to %d args\n", argc);
305240679Sbrian  }
305347849Sbrian  command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 1, getpid());
305440679Sbrian
305540679Sbrian  ptr = title;
305640679Sbrian  remaining = sizeof title - 1;
305740679Sbrian  for (f = 0; f < argc && remaining; f++) {
305840679Sbrian    if (f) {
305940679Sbrian      *ptr++ = ' ';
306040679Sbrian      remaining--;
306140679Sbrian    }
306240679Sbrian    len = strlen(argv[f]);
306340679Sbrian    if (len > remaining)
306440679Sbrian      len = remaining;
306540679Sbrian    memcpy(ptr, argv[f], len);
306640679Sbrian    remaining -= len;
306740679Sbrian    ptr += len;
306840679Sbrian  }
306940679Sbrian  *ptr = '\0';
307040679Sbrian
307164698Sbrian  SetTitle(title);
307240679Sbrian
307340679Sbrian  return 0;
307440679Sbrian}
3075