command.c revision 81033
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 81033 2001-08-02 10:16:32Z 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"
736059Samurai#include "ipcp.h"
7450059Sbrian#ifndef NONAT
7551075Sbrian#include "nat_cmd.h"
7631343Sbrian#endif
7725630Sbrian#include "systems.h"
7836285Sbrian#include "filter.h"
7936285Sbrian#include "descriptor.h"
8030715Sbrian#include "main.h"
8130715Sbrian#include "route.h"
8230715Sbrian#include "ccp.h"
8331080Sbrian#include "auth.h"
8436285Sbrian#include "async.h"
8536285Sbrian#include "link.h"
8636285Sbrian#include "physical.h"
8736285Sbrian#include "mp.h"
8843313Sbrian#ifndef NORADIUS
8943313Sbrian#include "radius.h"
9043313Sbrian#endif
9136285Sbrian#include "bundle.h"
9236285Sbrian#include "server.h"
9336285Sbrian#include "prompt.h"
9436285Sbrian#include "chat.h"
9536285Sbrian#include "chap.h"
9638174Sbrian#include "cbcp.h"
9736285Sbrian#include "datalink.h"
9840561Sbrian#include "iface.h"
9953298Sbrian#include "id.h"
1006059Samurai
10136285Sbrian/* ``set'' values */
10236285Sbrian#define	VAR_AUTHKEY	0
10336285Sbrian#define	VAR_DIAL	1
10436285Sbrian#define	VAR_LOGIN	2
10536285Sbrian#define	VAR_AUTHNAME	3
10636285Sbrian#define	VAR_AUTOLOAD	4
10736285Sbrian#define	VAR_WINSIZE	5
10836285Sbrian#define	VAR_DEVICE	6
10936285Sbrian#define	VAR_ACCMAP	7
11036285Sbrian#define	VAR_MRRU	8
11136285Sbrian#define	VAR_MRU		9
11236285Sbrian#define	VAR_MTU		10
11336285Sbrian#define	VAR_OPENMODE	11
11436285Sbrian#define	VAR_PHONE	12
11536285Sbrian#define	VAR_HANGUP	13
11636285Sbrian#define	VAR_IDLETIMEOUT	14
11736285Sbrian#define	VAR_LQRPERIOD	15
11836285Sbrian#define	VAR_LCPRETRY	16
11936285Sbrian#define	VAR_CHAPRETRY	17
12036285Sbrian#define	VAR_PAPRETRY	18
12136285Sbrian#define	VAR_CCPRETRY	19
12236285Sbrian#define	VAR_IPCPRETRY	20
12336285Sbrian#define	VAR_DNS		21
12436285Sbrian#define	VAR_NBNS	22
12536285Sbrian#define	VAR_MODE	23
12638174Sbrian#define	VAR_CALLBACK	24
12738174Sbrian#define	VAR_CBCP	25
12838544Sbrian#define	VAR_CHOKED	26
12940665Sbrian#define	VAR_SENDPIPE	27
13040665Sbrian#define	VAR_RECVPIPE	28
13143313Sbrian#define	VAR_RADIUS	29
13244073Sbrian#define	VAR_CD		30
13346686Sbrian#define	VAR_PARITY	31
13446686Sbrian#define VAR_CRTSCTS	32
13550867Sbrian#define VAR_URGENTPORTS	33
13652488Sbrian#define	VAR_LOGOUT	34
13761534Sbrian#define	VAR_IFQUEUE	35
13878411Sbrian#define	VAR_MPPE	36
1396059Samurai
14036285Sbrian/* ``accept|deny|disable|enable'' masks */
14136285Sbrian#define NEG_HISMASK (1)
14236285Sbrian#define NEG_MYMASK (2)
14336285Sbrian
14436285Sbrian/* ``accept|deny|disable|enable'' values */
14536285Sbrian#define NEG_ACFCOMP	40
14644106Sbrian#define NEG_CHAP05	41
14744106Sbrian#define NEG_CHAP80	42
14844106Sbrian#define NEG_CHAP80LM	43
14944106Sbrian#define NEG_DEFLATE	44
15047858Sbrian#define NEG_DNS		45
15147858Sbrian#define NEG_ENDDISC	46
15247858Sbrian#define NEG_LQR		47
15347858Sbrian#define NEG_PAP		48
15447858Sbrian#define NEG_PPPDDEFLATE	49
15547858Sbrian#define NEG_PRED1	50
15647858Sbrian#define NEG_PROTOCOMP	51
15747858Sbrian#define NEG_SHORTSEQ	52
15847858Sbrian#define NEG_VJCOMP	53
15967910Sbrian#define NEG_MPPE	54
16067910Sbrian#define NEG_CHAP81	55
16136285Sbrian
16278410Sbrianconst char Version[] = "2.3.2";
16336285Sbrian
16436285Sbrianstatic int ShowCommand(struct cmdargs const *);
16536285Sbrianstatic int TerminalCommand(struct cmdargs const *);
16636285Sbrianstatic int QuitCommand(struct cmdargs const *);
16736285Sbrianstatic int OpenCommand(struct cmdargs const *);
16836285Sbrianstatic int CloseCommand(struct cmdargs const *);
16936285Sbrianstatic int DownCommand(struct cmdargs const *);
17036285Sbrianstatic int SetCommand(struct cmdargs const *);
17136285Sbrianstatic int LinkCommand(struct cmdargs const *);
17236285Sbrianstatic int AddCommand(struct cmdargs const *);
17336285Sbrianstatic int DeleteCommand(struct cmdargs const *);
17436285Sbrianstatic int NegotiateCommand(struct cmdargs const *);
17536934Sbrianstatic int ClearCommand(struct cmdargs const *);
17640561Sbrianstatic int RunListCommand(struct cmdargs const *);
17740561Sbrianstatic int IfaceAddCommand(struct cmdargs const *);
17840561Sbrianstatic int IfaceDeleteCommand(struct cmdargs const *);
17940561Sbrianstatic int IfaceClearCommand(struct cmdargs const *);
18040679Sbrianstatic int SetProcTitle(struct cmdargs const *);
18150059Sbrian#ifndef NONAT
18258867Sbrianstatic int NatEnable(struct cmdargs const *);
18358867Sbrianstatic int NatOption(struct cmdargs const *);
18431343Sbrian#endif
1856059Samurai
18636285Sbrianstatic const char *
18736285Sbrianshowcx(struct cmdtab const *cmd)
18836285Sbrian{
18936285Sbrian  if (cmd->lauth & LOCAL_CX)
19036285Sbrian    return "(c)";
19136285Sbrian  else if (cmd->lauth & LOCAL_CX_OPT)
19236285Sbrian    return "(o)";
19336285Sbrian
19436285Sbrian  return "";
19536285Sbrian}
19636285Sbrian
1976059Samuraistatic int
19831343SbrianHelpCommand(struct cmdargs const *arg)
1996059Samurai{
20028679Sbrian  struct cmdtab const *cmd;
20136285Sbrian  int n, cmax, dmax, cols, cxlen;
20236285Sbrian  const char *cx;
2036059Samurai
20436285Sbrian  if (!arg->prompt) {
20536285Sbrian    log_Printf(LogWARN, "help: Cannot help without a prompt\n");
20626516Sbrian    return 0;
20736285Sbrian  }
20826516Sbrian
20936285Sbrian  if (arg->argc > arg->argn) {
21036285Sbrian    for (cmd = arg->cmdtab; cmd->name || cmd->alias; cmd++)
21136285Sbrian      if ((cmd->lauth & arg->prompt->auth) &&
21236285Sbrian          ((cmd->name && !strcasecmp(cmd->name, arg->argv[arg->argn])) ||
21336285Sbrian           (cmd->alias && !strcasecmp(cmd->alias, arg->argv[arg->argn])))) {
21436285Sbrian	prompt_Printf(arg->prompt, "%s %s\n", cmd->syntax, showcx(cmd));
21528679Sbrian	return 0;
2166059Samurai      }
21726516Sbrian    return -1;
2186059Samurai  }
21936285Sbrian
22031372Sbrian  cmax = dmax = 0;
22136285Sbrian  for (cmd = arg->cmdtab; cmd->func; cmd++)
22236285Sbrian    if (cmd->name && (cmd->lauth & arg->prompt->auth)) {
22336285Sbrian      if ((n = strlen(cmd->name) + strlen(showcx(cmd))) > cmax)
22431372Sbrian        cmax = n;
22531372Sbrian      if ((n = strlen(cmd->helpmes)) > dmax)
22631372Sbrian        dmax = n;
22731372Sbrian    }
22831372Sbrian
22931372Sbrian  cols = 80 / (dmax + cmax + 3);
2306059Samurai  n = 0;
23136285Sbrian  prompt_Printf(arg->prompt, "(o) = Optional context,"
23236285Sbrian                " (c) = Context required\n");
23336285Sbrian  for (cmd = arg->cmdtab; cmd->func; cmd++)
23436285Sbrian    if (cmd->name && (cmd->lauth & arg->prompt->auth)) {
23536285Sbrian      cx = showcx(cmd);
23636285Sbrian      cxlen = cmax - strlen(cmd->name);
23740482Sbrian      if (n % cols != 0)
23840482Sbrian        prompt_Printf(arg->prompt, " ");
23940482Sbrian      prompt_Printf(arg->prompt, "%s%-*.*s: %-*.*s",
24036285Sbrian              cmd->name, cxlen, cxlen, cx, dmax, dmax, cmd->helpmes);
24131372Sbrian      if (++n % cols == 0)
24236285Sbrian        prompt_Printf(arg->prompt, "\n");
2436059Samurai    }
24431372Sbrian  if (n % cols != 0)
24536285Sbrian    prompt_Printf(arg->prompt, "\n");
24626516Sbrian
24726516Sbrian  return 0;
2486059Samurai}
2496059Samurai
25036285Sbrianstatic int
25163484SbrianIdentCommand(struct cmdargs const *arg)
25263484Sbrian{
25363484Sbrian  int f, pos;
25463484Sbrian
25563484Sbrian  *arg->cx->physical->link.lcp.cfg.ident = '\0';
25663484Sbrian
25763484Sbrian  for (pos = 0, f = arg->argn; f < arg->argc; f++)
25863484Sbrian    pos += snprintf(arg->cx->physical->link.lcp.cfg.ident + pos,
25963484Sbrian                    sizeof arg->cx->physical->link.lcp.cfg.ident - pos, "%s%s",
26063484Sbrian                    f == arg->argn ? "" : " ", arg->argv[f]);
26163484Sbrian
26263484Sbrian  return 0;
26363484Sbrian}
26463484Sbrian
26563484Sbrianstatic int
26663484SbrianSendIdentification(struct cmdargs const *arg)
26763484Sbrian{
26863484Sbrian  if (arg->cx->state < DATALINK_LCP) {
26963484Sbrian    log_Printf(LogWARN, "sendident: link has not reached LCP\n");
27063484Sbrian    return 2;
27163484Sbrian  }
27263484Sbrian  return lcp_SendIdentification(&arg->cx->physical->link.lcp) ? 0 : 1;
27363484Sbrian}
27463484Sbrian
27563484Sbrianstatic int
27636285SbrianCloneCommand(struct cmdargs const *arg)
2776059Samurai{
27836285Sbrian  char namelist[LINE_LEN];
27936285Sbrian  char *name;
28036285Sbrian  int f;
2816059Samurai
28236285Sbrian  if (arg->argc == arg->argn)
28336285Sbrian    return -1;
28436285Sbrian
28536285Sbrian  namelist[sizeof namelist - 1] = '\0';
28636285Sbrian  for (f = arg->argn; f < arg->argc; f++) {
28736285Sbrian    strncpy(namelist, arg->argv[f], sizeof namelist - 1);
28836285Sbrian    for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
28936285Sbrian      bundle_DatalinkClone(arg->bundle, arg->cx, name);
2906059Samurai  }
29136285Sbrian
29236285Sbrian  return 0;
2936059Samurai}
2946059Samurai
2956059Samuraistatic int
29636285SbrianRemoveCommand(struct cmdargs const *arg)
2976059Samurai{
29836285Sbrian  if (arg->argc != arg->argn)
29936285Sbrian    return -1;
30011336Samurai
30136285Sbrian  if (arg->cx->state != DATALINK_CLOSED) {
30236285Sbrian    log_Printf(LogWARN, "remove: Cannot delete links that aren't closed\n");
30336285Sbrian    return 2;
3046059Samurai  }
30526516Sbrian
30636285Sbrian  bundle_DatalinkRemove(arg->bundle, arg->cx);
30736285Sbrian  return 0;
30836285Sbrian}
30932711Sbrian
31036285Sbrianstatic int
31136285SbrianRenameCommand(struct cmdargs const *arg)
31236285Sbrian{
31336285Sbrian  if (arg->argc != arg->argn + 1)
31436285Sbrian    return -1;
31531121Sbrian
31636285Sbrian  if (bundle_RenameDatalink(arg->bundle, arg->cx, arg->argv[arg->argn]))
31736285Sbrian    return 0;
31836285Sbrian
31936285Sbrian  log_Printf(LogWARN, "%s -> %s: target name already exists\n",
32036285Sbrian             arg->cx->name, arg->argv[arg->argn]);
32136285Sbrian  return 1;
32236285Sbrian}
32336285Sbrian
32436285Sbrianint
32536285SbrianLoadCommand(struct cmdargs const *arg)
32636285Sbrian{
32740797Sbrian  const char *err;
32840797Sbrian  int n, mode;
32936285Sbrian
33040797Sbrian  mode = arg->bundle->phys_type.all;
33136285Sbrian
33240797Sbrian  if (arg->argn < arg->argc) {
33340797Sbrian    for (n = arg->argn; n < arg->argc; n++)
33440797Sbrian      if ((err = system_IsValid(arg->argv[n], arg->prompt, mode)) != NULL) {
33540797Sbrian        log_Printf(LogWARN, "%s: %s\n", arg->argv[n], err);
33640797Sbrian        return 1;
33740797Sbrian      }
33840797Sbrian
33940797Sbrian    for (n = arg->argn; n < arg->argc; n++) {
34040797Sbrian      bundle_SetLabel(arg->bundle, arg->argv[arg->argc - 1]);
34140797Sbrian      system_Select(arg->bundle, arg->argv[n], CONFFILE, arg->prompt, arg->cx);
34240797Sbrian    }
34340797Sbrian    bundle_SetLabel(arg->bundle, arg->argv[arg->argc - 1]);
34440797Sbrian  } else if ((err = system_IsValid("default", arg->prompt, mode)) != NULL) {
34540797Sbrian    log_Printf(LogWARN, "default: %s\n", err);
34636285Sbrian    return 1;
34736285Sbrian  } else {
34840797Sbrian    bundle_SetLabel(arg->bundle, "default");
34940797Sbrian    system_Select(arg->bundle, "default", CONFFILE, arg->prompt, arg->cx);
35040797Sbrian    bundle_SetLabel(arg->bundle, "default");
35136285Sbrian  }
35240797Sbrian
35326516Sbrian  return 0;
3546059Samurai}
3556059Samurai
35636285Sbrianint
35736285SbrianSaveCommand(struct cmdargs const *arg)
35836285Sbrian{
35936285Sbrian  log_Printf(LogWARN, "save command is not implemented (yet).\n");
36036285Sbrian  return 1;
36136285Sbrian}
36236285Sbrian
36310528Samuraistatic int
36436285SbrianDialCommand(struct cmdargs const *arg)
36528536Sbrian{
36636285Sbrian  int res;
36736285Sbrian
36836465Sbrian  if ((arg->cx && !(arg->cx->physical->type & (PHYS_INTERACTIVE|PHYS_AUTO)))
36936465Sbrian      || (!arg->cx &&
37036928Sbrian          (arg->bundle->phys_type.all & ~(PHYS_INTERACTIVE|PHYS_AUTO)))) {
37136285Sbrian    log_Printf(LogWARN, "Manual dial is only available for auto and"
37236285Sbrian              " interactive links\n");
37336285Sbrian    return 1;
37434536Sbrian  }
37536285Sbrian
37636285Sbrian  if (arg->argc > arg->argn && (res = LoadCommand(arg)) != 0)
37736285Sbrian    return res;
37836285Sbrian
37937993Sbrian  bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1);
38036285Sbrian
38136285Sbrian  return 0;
38228536Sbrian}
38328536Sbrian
38438628Sbrian#define isinword(ch) (isalnum(ch) || (ch) == '_')
38538628Sbrian
38638628Sbrianstatic char *
38738628Sbrianstrstrword(char *big, const char *little)
38838628Sbrian{
38938628Sbrian  /* Get the first occurance of the word ``little'' in ``big'' */
39038628Sbrian  char *pos;
39138628Sbrian  int len;
39238628Sbrian
39338628Sbrian  pos = big;
39438628Sbrian  len = strlen(little);
39538628Sbrian
39638628Sbrian  while ((pos = strstr(pos, little)) != NULL)
39747865Sbrian    if ((pos != big && isinword(pos[-1])) || isinword(pos[len]))
39847865Sbrian      pos++;
39947865Sbrian    else if (pos != big && pos[-1] == '\\')
40047865Sbrian      memmove(pos - 1, pos, strlen(pos) + 1);
40147865Sbrian    else
40238628Sbrian      break;
40338628Sbrian
40438628Sbrian  return pos;
40538628Sbrian}
40638628Sbrian
40738628Sbrianstatic char *
40838628Sbriansubst(char *tgt, const char *oldstr, const char *newstr)
40938628Sbrian{
41038628Sbrian  /* tgt is a malloc()d area... realloc() as necessary */
41138628Sbrian  char *word, *ntgt;
41238628Sbrian  int ltgt, loldstr, lnewstr, pos;
41338628Sbrian
41438628Sbrian  if ((word = strstrword(tgt, oldstr)) == NULL)
41538628Sbrian    return tgt;
41638628Sbrian
41738628Sbrian  ltgt = strlen(tgt) + 1;
41838628Sbrian  loldstr = strlen(oldstr);
41938628Sbrian  lnewstr = strlen(newstr);
42038628Sbrian  do {
42138628Sbrian    pos = word - tgt;
42238628Sbrian    if (loldstr > lnewstr)
42338628Sbrian      bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr);
42438628Sbrian    if (loldstr != lnewstr) {
42538628Sbrian      ntgt = realloc(tgt, ltgt += lnewstr - loldstr);
42638628Sbrian      if (ntgt == NULL)
42738628Sbrian        break;			/* Oh wonderful ! */
42838628Sbrian      word = ntgt + pos;
42938628Sbrian      tgt = ntgt;
43038628Sbrian    }
43138628Sbrian    if (lnewstr > loldstr)
43238628Sbrian      bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr);
43338628Sbrian    bcopy(newstr, word, lnewstr);
43438628Sbrian  } while ((word = strstrword(word, oldstr)));
43538628Sbrian
43638628Sbrian  return tgt;
43738628Sbrian}
43838628Sbrian
43943888Sbrianvoid
44043888Sbriancommand_Expand(char **nargv, int argc, char const *const *oargv,
44147849Sbrian               struct bundle *bundle, int inc0, pid_t pid)
44238628Sbrian{
44338628Sbrian  int arg;
44447849Sbrian  char pidstr[12];
44538628Sbrian
44641755Sbrian  if (inc0)
44741755Sbrian    arg = 0;		/* Start at arg 0 */
44841755Sbrian  else {
44941755Sbrian    nargv[0] = strdup(oargv[0]);
45041755Sbrian    arg = 1;
45141755Sbrian  }
45247849Sbrian  snprintf(pidstr, sizeof pidstr, "%d", (int)pid);
45341755Sbrian  for (; arg < argc; arg++) {
45438629Sbrian    nargv[arg] = strdup(oargv[arg]);
45538629Sbrian    nargv[arg] = subst(nargv[arg], "HISADDR",
45638628Sbrian                       inet_ntoa(bundle->ncp.ipcp.peer_ip));
45738629Sbrian    nargv[arg] = subst(nargv[arg], "AUTHNAME", bundle->cfg.auth.name);
45840561Sbrian    nargv[arg] = subst(nargv[arg], "INTERFACE", bundle->iface->name);
45938628Sbrian    nargv[arg] = subst(nargv[arg], "MYADDR", inet_ntoa(bundle->ncp.ipcp.my_ip));
46038629Sbrian    nargv[arg] = subst(nargv[arg], "USER", bundle->ncp.mp.peer.authname);
46138629Sbrian    nargv[arg] = subst(nargv[arg], "PEER_ENDDISC",
46238629Sbrian                       mp_Enddisc(bundle->ncp.mp.peer.enddisc.class,
46338629Sbrian                                  bundle->ncp.mp.peer.enddisc.address,
46438629Sbrian                                  bundle->ncp.mp.peer.enddisc.len));
46538629Sbrian    nargv[arg] = subst(nargv[arg], "ENDDISC",
46638629Sbrian                       mp_Enddisc(bundle->ncp.mp.cfg.enddisc.class,
46738629Sbrian                                  bundle->ncp.mp.cfg.enddisc.address,
46838629Sbrian                                  bundle->ncp.mp.cfg.enddisc.len));
46947849Sbrian    nargv[arg] = subst(nargv[arg], "PROCESSID", pidstr);
47038629Sbrian    nargv[arg] = subst(nargv[arg], "LABEL", bundle_GetLabel(bundle));
47158044Sbrian    nargv[arg] = subst(nargv[arg], "DNS0",
47258044Sbrian                       inet_ntoa(bundle->ncp.ipcp.ns.dns[0]));
47358044Sbrian    nargv[arg] = subst(nargv[arg], "DNS1",
47458044Sbrian                       inet_ntoa(bundle->ncp.ipcp.ns.dns[1]));
47563484Sbrian    nargv[arg] = subst(nargv[arg], "VERSION", Version);
47663484Sbrian    nargv[arg] = subst(nargv[arg], "COMPILATIONDATE", __DATE__);
47738628Sbrian  }
47838628Sbrian  nargv[arg] = NULL;
47938628Sbrian}
48038628Sbrian
48128536Sbrianstatic int
48231343SbrianShellCommand(struct cmdargs const *arg, int bg)
48310528Samurai{
48410528Samurai  const char *shell;
48547849Sbrian  pid_t shpid, pid;
48620813Sjkh
48718856Ssos#ifdef SHELL_ONLY_INTERACTIVELY
48826911Sbrian  /* we're only allowed to shell when we run ppp interactively */
48936285Sbrian  if (arg->prompt && arg->prompt->owner) {
49036285Sbrian    log_Printf(LogWARN, "Can't start a shell from a network connection\n");
49126516Sbrian    return 1;
49210528Samurai  }
49326911Sbrian#endif
49428679Sbrian
49536285Sbrian  if (arg->argc == arg->argn) {
49636285Sbrian    if (!arg->prompt) {
49736285Sbrian      log_Printf(LogWARN, "Can't start an interactive shell from"
49836285Sbrian                " a config file\n");
49928381Sbrian      return 1;
50036285Sbrian    } else if (arg->prompt->owner) {
50136285Sbrian      log_Printf(LogWARN, "Can't start an interactive shell from"
50236285Sbrian                " a socket connection\n");
50336285Sbrian      return 1;
50428381Sbrian    } else if (bg) {
50536285Sbrian      log_Printf(LogWARN, "Can only start an interactive shell in"
50628679Sbrian		" the foreground mode\n");
50728381Sbrian      return 1;
50828381Sbrian    }
50934536Sbrian  }
51034536Sbrian
51147849Sbrian  pid = getpid();
51228679Sbrian  if ((shpid = fork()) == 0) {
51336285Sbrian    int i, fd;
51418531Sbde
51536285Sbrian    if ((shell = getenv("SHELL")) == 0)
51636285Sbrian      shell = _PATH_BSHELL;
51732017Sbrian
51836285Sbrian    timer_TermService();
51936285Sbrian
52036285Sbrian    if (arg->prompt)
52136285Sbrian      fd = arg->prompt->fd_out;
52236285Sbrian    else if ((fd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
52336285Sbrian      log_Printf(LogALERT, "Failed to open %s: %s\n",
52436285Sbrian                _PATH_DEVNULL, strerror(errno));
52528679Sbrian      exit(1);
52628679Sbrian    }
52749976Sbrian    dup2(fd, STDIN_FILENO);
52849976Sbrian    dup2(fd, STDOUT_FILENO);
52949976Sbrian    dup2(fd, STDERR_FILENO);
53049976Sbrian    for (i = getdtablesize(); i > STDERR_FILENO; i--)
53149976Sbrian      fcntl(i, F_SETFD, 1);
53226516Sbrian
53364802Sbrian#ifndef NOSUID
53455252Sbrian    setuid(ID0realuid());
53564802Sbrian#endif
53636285Sbrian    if (arg->argc > arg->argn) {
53728679Sbrian      /* substitute pseudo args */
53838628Sbrian      char *argv[MAXARGS];
53938628Sbrian      int argc = arg->argc - arg->argn;
54038628Sbrian
54138628Sbrian      if (argc >= sizeof argv / sizeof argv[0]) {
54238628Sbrian        argc = sizeof argv / sizeof argv[0] - 1;
54338628Sbrian        log_Printf(LogWARN, "Truncating shell command to %d args\n", argc);
54431343Sbrian      }
54547849Sbrian      command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 0, pid);
54628679Sbrian      if (bg) {
54728679Sbrian	pid_t p;
54810528Samurai
54928679Sbrian	p = getpid();
55028679Sbrian	if (daemon(1, 1) == -1) {
55136832Sbrian	  log_Printf(LogERROR, "%d: daemon: %s\n", (int)p, strerror(errno));
55228679Sbrian	  exit(1);
55328679Sbrian	}
55436285Sbrian      } else if (arg->prompt)
55536285Sbrian        printf("ppp: Pausing until %s finishes\n", arg->argv[arg->argn]);
55631343Sbrian      execvp(argv[0], argv);
55730316Sbrian    } else {
55836285Sbrian      if (arg->prompt)
55932017Sbrian        printf("ppp: Pausing until %s finishes\n", shell);
56036285Sbrian      prompt_TtyOldMode(arg->prompt);
56179450Sbrian      execl(shell, shell, (char *)NULL);
56230316Sbrian    }
56320813Sjkh
56440665Sbrian    log_Printf(LogWARN, "exec() of %s failed: %s\n",
56540665Sbrian              arg->argc > arg->argn ? arg->argv[arg->argn] : shell,
56640665Sbrian              strerror(errno));
56749976Sbrian    _exit(255);
56810528Samurai  }
56936285Sbrian
57036285Sbrian  if (shpid == (pid_t) - 1)
57136285Sbrian    log_Printf(LogERROR, "Fork failed: %s\n", strerror(errno));
57236285Sbrian  else {
57310528Samurai    int status;
57431343Sbrian    waitpid(shpid, &status, 0);
57510528Samurai  }
57620813Sjkh
57736285Sbrian  if (arg->prompt && !arg->prompt->owner)
57836285Sbrian    prompt_TtyCommandMode(arg->prompt);
57920813Sjkh
58036285Sbrian  return 0;
58110528Samurai}
58210528Samurai
58331343Sbrianstatic int
58431343SbrianBgShellCommand(struct cmdargs const *arg)
58531343Sbrian{
58636285Sbrian  if (arg->argc == arg->argn)
58731343Sbrian    return -1;
58831343Sbrian  return ShellCommand(arg, 1);
58931343Sbrian}
59031343Sbrian
59131343Sbrianstatic int
59231343SbrianFgShellCommand(struct cmdargs const *arg)
59331343Sbrian{
59431343Sbrian  return ShellCommand(arg, 0);
59531343Sbrian}
59631343Sbrian
59758044Sbrianstatic int
59858044SbrianResolvCommand(struct cmdargs const *arg)
59958044Sbrian{
60058044Sbrian  if (arg->argc == arg->argn + 1) {
60158044Sbrian    if (!strcasecmp(arg->argv[arg->argn], "reload"))
60258044Sbrian      ipcp_LoadDNS(&arg->bundle->ncp.ipcp);
60358044Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "restore"))
60458044Sbrian      ipcp_RestoreDNS(&arg->bundle->ncp.ipcp);
60558044Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "rewrite"))
60658044Sbrian      ipcp_WriteDNS(&arg->bundle->ncp.ipcp);
60758044Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "readonly"))
60858044Sbrian      arg->bundle->ncp.ipcp.ns.writable = 0;
60958044Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "writable"))
61058044Sbrian      arg->bundle->ncp.ipcp.ns.writable = 1;
61158044Sbrian    else
61258044Sbrian      return -1;
61358044Sbrian
61458044Sbrian    return 0;
61558044Sbrian  }
61658044Sbrian
61758044Sbrian  return -1;
61858044Sbrian}
61958044Sbrian
62050059Sbrian#ifndef NONAT
62158867Sbrianstatic struct cmdtab const NatCommands[] =
62240561Sbrian{
62350059Sbrian  {"addr", NULL, nat_RedirectAddr, LOCAL_AUTH,
62450059Sbrian   "static address translation", "nat addr [addr_local addr_alias]"},
62558867Sbrian  {"deny_incoming", NULL, NatOption, LOCAL_AUTH,
62650059Sbrian   "stop incoming connections", "nat deny_incoming yes|no",
62740561Sbrian   (const void *) PKT_ALIAS_DENY_INCOMING},
62858867Sbrian  {"enable", NULL, NatEnable, LOCAL_AUTH,
62950059Sbrian   "enable NAT", "nat enable yes|no"},
63058867Sbrian  {"log", NULL, NatOption, LOCAL_AUTH,
63150059Sbrian   "log NAT link creation", "nat log yes|no",
63240561Sbrian   (const void *) PKT_ALIAS_LOG},
63350059Sbrian  {"port", NULL, nat_RedirectPort, LOCAL_AUTH, "port redirection",
63450059Sbrian   "nat port proto localaddr:port[-port] aliasport[-aliasport]"},
63579433Sbrian  {"proto", NULL, nat_RedirectProto, LOCAL_AUTH, "protocol redirection",
63679433Sbrian   "nat proto proto localIP [publicIP [remoteIP]]"},
63750059Sbrian  {"proxy", NULL, nat_ProxyRule, LOCAL_AUTH,
63850059Sbrian   "proxy control", "nat proxy server host[:port] ..."},
63981033Sbrian#ifndef NO_FW_PUNCH
64081033Sbrian  {"punch_fw", NULL, nat_PunchFW, LOCAL_AUTH,
64181033Sbrian   "firewall control", "nat punch_fw [base count]"},
64281033Sbrian#endif
64358867Sbrian  {"same_ports", NULL, NatOption, LOCAL_AUTH,
64450059Sbrian   "try to leave port numbers unchanged", "nat same_ports yes|no",
64540561Sbrian   (const void *) PKT_ALIAS_SAME_PORTS},
64658867Sbrian  {"target", NULL, nat_SetTarget, LOCAL_AUTH,
64758867Sbrian   "Default address for incoming connections", "nat target addr" },
64858867Sbrian  {"unregistered_only", NULL, NatOption, LOCAL_AUTH,
64950059Sbrian   "translate unregistered (private) IP address space only",
65050059Sbrian   "nat unregistered_only yes|no",
65140561Sbrian   (const void *) PKT_ALIAS_UNREGISTERED_ONLY},
65258867Sbrian  {"use_sockets", NULL, NatOption, LOCAL_AUTH,
65350059Sbrian   "allocate host sockets", "nat use_sockets yes|no",
65440561Sbrian   (const void *) PKT_ALIAS_USE_SOCKETS},
65540561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
65658867Sbrian   "Display this message", "nat help|? [command]", NatCommands},
65740561Sbrian  {NULL, NULL, NULL},
65840561Sbrian};
65940561Sbrian#endif
66040561Sbrian
66140561Sbrianstatic struct cmdtab const AllowCommands[] = {
66240561Sbrian  {"modes", "mode", AllowModes, LOCAL_AUTH,
66340561Sbrian  "Only allow certain ppp modes", "allow modes mode..."},
66440561Sbrian  {"users", "user", AllowUsers, LOCAL_AUTH,
66540561Sbrian  "Only allow ppp access to certain users", "allow users logname..."},
66640561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
66740561Sbrian  "Display this message", "allow help|? [command]", AllowCommands},
66840561Sbrian  {NULL, NULL, NULL},
66940561Sbrian};
67040561Sbrian
67140561Sbrianstatic struct cmdtab const IfaceCommands[] =
67240561Sbrian{
67340561Sbrian  {"add", NULL, IfaceAddCommand, LOCAL_AUTH,
67440561Sbrian   "Add iface address", "iface add addr[/bits| mask] peer", NULL},
67540561Sbrian  {NULL, "add!", IfaceAddCommand, LOCAL_AUTH,
67640561Sbrian   "Add or change an iface address", "iface add! addr[/bits| mask] peer",
67740561Sbrian   (void *)1},
67840561Sbrian  {"clear", NULL, IfaceClearCommand, LOCAL_AUTH,
67940561Sbrian   "Clear iface address(es)", "iface clear"},
68040561Sbrian  {"delete", "rm", IfaceDeleteCommand, LOCAL_AUTH,
68140561Sbrian   "Delete iface address", "iface delete addr", NULL},
68240561Sbrian  {NULL, "rm!", IfaceDeleteCommand, LOCAL_AUTH,
68340561Sbrian   "Delete iface address", "iface delete addr", (void *)1},
68440561Sbrian  {NULL, "delete!", IfaceDeleteCommand, LOCAL_AUTH,
68540561Sbrian   "Delete iface address", "iface delete addr", (void *)1},
68640561Sbrian  {"show", NULL, iface_Show, LOCAL_AUTH,
68740561Sbrian   "Show iface address(es)", "iface show"},
68840561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
68950059Sbrian   "Display this message", "nat help|? [command]", IfaceCommands},
69040561Sbrian  {NULL, NULL, NULL},
69140561Sbrian};
69240561Sbrian
69330715Sbrianstatic struct cmdtab const Commands[] = {
69436285Sbrian  {"accept", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
69528679Sbrian  "accept option request", "accept option .."},
69628679Sbrian  {"add", NULL, AddCommand, LOCAL_AUTH,
69732109Sbrian  "add route", "add dest mask gateway", NULL},
69836285Sbrian  {NULL, "add!", AddCommand, LOCAL_AUTH,
69932109Sbrian  "add or change route", "add! dest mask gateway", (void *)1},
70040561Sbrian  {"allow", "auth", RunListCommand, LOCAL_AUTH,
70140561Sbrian  "Allow ppp access", "allow users|modes ....", AllowCommands},
70228679Sbrian  {"bg", "!bg", BgShellCommand, LOCAL_AUTH,
70331372Sbrian  "Run a background command", "[!]bg command"},
70436934Sbrian  {"clear", NULL, ClearCommand, LOCAL_AUTH | LOCAL_CX_OPT,
70546686Sbrian  "Clear throughput statistics",
70646686Sbrian  "clear ipcp|physical [current|overall|peak]..."},
70736285Sbrian  {"clone", NULL, CloneCommand, LOCAL_AUTH | LOCAL_CX,
70836285Sbrian  "Clone a link", "clone newname..."},
70936285Sbrian  {"close", NULL, CloseCommand, LOCAL_AUTH | LOCAL_CX_OPT,
71036285Sbrian  "Close an FSM", "close [lcp|ccp]"},
71128679Sbrian  {"delete", NULL, DeleteCommand, LOCAL_AUTH,
71232109Sbrian  "delete route", "delete dest", NULL},
71336285Sbrian  {NULL, "delete!", DeleteCommand, LOCAL_AUTH,
71432109Sbrian  "delete a route if it exists", "delete! dest", (void *)1},
71536285Sbrian  {"deny", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
71628679Sbrian  "Deny option request", "deny option .."},
71736285Sbrian  {"dial", "call", DialCommand, LOCAL_AUTH | LOCAL_CX_OPT,
71840797Sbrian  "Dial and login", "dial|call [system ...]", NULL},
71936285Sbrian  {"disable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
72028679Sbrian  "Disable option", "disable option .."},
72136285Sbrian  {"down", NULL, DownCommand, LOCAL_AUTH | LOCAL_CX_OPT,
72246686Sbrian  "Generate a down event", "down [ccp|lcp]"},
72336285Sbrian  {"enable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
72428679Sbrian  "Enable option", "enable option .."},
72563484Sbrian  {"ident", NULL, IdentCommand, LOCAL_AUTH | LOCAL_CX,
72663484Sbrian  "Set the link identity", "ident text..."},
72740561Sbrian  {"iface", "interface", RunListCommand, LOCAL_AUTH,
72840561Sbrian  "interface control", "iface option ...", IfaceCommands},
72936285Sbrian  {"link", "datalink", LinkCommand, LOCAL_AUTH,
73036285Sbrian  "Link specific commands", "link name command ..."},
73137008Sbrian  {"load", NULL, LoadCommand, LOCAL_AUTH | LOCAL_CX_OPT,
73240797Sbrian  "Load settings", "load [system ...]"},
73350059Sbrian#ifndef NONAT
73450059Sbrian  {"nat", "alias", RunListCommand, LOCAL_AUTH,
73558867Sbrian  "NAT control", "nat option yes|no", NatCommands},
73650059Sbrian#endif
73736285Sbrian  {"open", NULL, OpenCommand, LOCAL_AUTH | LOCAL_CX_OPT,
73837955Sbrian  "Open an FSM", "open! [lcp|ccp|ipcp]", (void *)1},
73936285Sbrian  {"passwd", NULL, PasswdCommand, LOCAL_NO_AUTH,
74036285Sbrian  "Password for manipulation", "passwd LocalPassword"},
74136285Sbrian  {"quit", "bye", QuitCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
74236285Sbrian  "Quit PPP program", "quit|bye [all]"},
74336285Sbrian  {"remove", "rm", RemoveCommand, LOCAL_AUTH | LOCAL_CX,
74436285Sbrian  "Remove a link", "remove"},
74536285Sbrian  {"rename", "mv", RenameCommand, LOCAL_AUTH | LOCAL_CX,
74636285Sbrian  "Rename a link", "rename name"},
74758044Sbrian  {"resolv", NULL, ResolvCommand, LOCAL_AUTH,
74858044Sbrian  "Manipulate resolv.conf", "resolv readonly|reload|restore|rewrite|writable"},
74928679Sbrian  {"save", NULL, SaveCommand, LOCAL_AUTH,
75028679Sbrian  "Save settings", "save"},
75163484Sbrian  {"sendident", NULL, SendIdentification, LOCAL_AUTH | LOCAL_CX,
75263484Sbrian  "Transmit the link identity", "sendident"},
75336285Sbrian  {"set", "setup", SetCommand, LOCAL_AUTH | LOCAL_CX_OPT,
75428679Sbrian  "Set parameters", "set[up] var value"},
75528679Sbrian  {"shell", "!", FgShellCommand, LOCAL_AUTH,
75628679Sbrian  "Run a subshell", "shell|! [sh command]"},
75736285Sbrian  {"show", NULL, ShowCommand, LOCAL_AUTH | LOCAL_CX_OPT,
75831372Sbrian  "Show status and stats", "show var"},
75936285Sbrian  {"term", NULL, TerminalCommand, LOCAL_AUTH | LOCAL_CX,
76031372Sbrian  "Enter terminal mode", "term"},
76128679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
76231343Sbrian  "Display this message", "help|? [command]", Commands},
76328679Sbrian  {NULL, NULL, NULL},
7646059Samurai};
7656059Samurai
76628536Sbrianstatic int
76731343SbrianShowEscape(struct cmdargs const *arg)
7686059Samurai{
76936285Sbrian  if (arg->cx->physical->async.cfg.EscMap[32]) {
77036285Sbrian    int code, bit;
77136285Sbrian    const char *sep = "";
7726059Samurai
77326516Sbrian    for (code = 0; code < 32; code++)
77436285Sbrian      if (arg->cx->physical->async.cfg.EscMap[code])
77528679Sbrian	for (bit = 0; bit < 8; bit++)
77636285Sbrian	  if (arg->cx->physical->async.cfg.EscMap[code] & (1 << bit)) {
77736285Sbrian	    prompt_Printf(arg->prompt, "%s0x%02x", sep, (code << 3) + bit);
77836285Sbrian            sep = ", ";
77936285Sbrian          }
78036285Sbrian    prompt_Printf(arg->prompt, "\n");
7816059Samurai  }
78231077Sbrian  return 0;
7836059Samurai}
7846059Samurai
78528679Sbrianstatic int
78636285SbrianShowTimerList(struct cmdargs const *arg)
7876059Samurai{
78836285Sbrian  timer_Show(0, arg->prompt);
78931077Sbrian  return 0;
7906059Samurai}
7916059Samurai
79228679Sbrianstatic int
79331343SbrianShowStopped(struct cmdargs const *arg)
79428327Sbrian{
79536285Sbrian  prompt_Printf(arg->prompt, " Stopped Timer:  LCP: ");
79636285Sbrian  if (!arg->cx->physical->link.lcp.fsm.StoppedTimer.load)
79736285Sbrian    prompt_Printf(arg->prompt, "Disabled");
79828327Sbrian  else
79936285Sbrian    prompt_Printf(arg->prompt, "%ld secs",
80036285Sbrian                  arg->cx->physical->link.lcp.fsm.StoppedTimer.load / SECTICKS);
80128461Sbrian
80236285Sbrian  prompt_Printf(arg->prompt, ", CCP: ");
80336285Sbrian  if (!arg->cx->physical->link.ccp.fsm.StoppedTimer.load)
80436285Sbrian    prompt_Printf(arg->prompt, "Disabled");
80528461Sbrian  else
80636285Sbrian    prompt_Printf(arg->prompt, "%ld secs",
80736285Sbrian                  arg->cx->physical->link.ccp.fsm.StoppedTimer.load / SECTICKS);
80828461Sbrian
80936285Sbrian  prompt_Printf(arg->prompt, "\n");
81028461Sbrian
81131077Sbrian  return 0;
81228327Sbrian}
81328327Sbrian
81428679Sbrianstatic int
81531343SbrianShowVersion(struct cmdargs const *arg)
8166059Samurai{
81751026Sbrian  prompt_Printf(arg->prompt, "PPP Version %s - %s\n", Version, __DATE__);
81831077Sbrian  return 0;
8196059Samurai}
8206059Samurai
82128679Sbrianstatic int
82236285SbrianShowProtocolStats(struct cmdargs const *arg)
82326326Sbrian{
82436285Sbrian  struct link *l = command_ChooseLink(arg);
82526326Sbrian
82636285Sbrian  prompt_Printf(arg->prompt, "%s:\n", l->name);
82736285Sbrian  link_ReportProtocolStatus(l, arg->prompt);
82831077Sbrian  return 0;
82926326Sbrian}
83026326Sbrian
83130715Sbrianstatic struct cmdtab const ShowCommands[] = {
83236285Sbrian  {"bundle", NULL, bundle_ShowStatus, LOCAL_AUTH,
83336285Sbrian  "bundle details", "show bundle"},
83436285Sbrian  {"ccp", NULL, ccp_ReportStatus, LOCAL_AUTH | LOCAL_CX_OPT,
83536285Sbrian  "CCP status", "show cpp"},
83636285Sbrian  {"compress", NULL, sl_Show, LOCAL_AUTH,
83736285Sbrian  "VJ compression stats", "show compress"},
83836285Sbrian  {"escape", NULL, ShowEscape, LOCAL_AUTH | LOCAL_CX,
83936285Sbrian  "escape characters", "show escape"},
84036285Sbrian  {"filter", NULL, filter_Show, LOCAL_AUTH,
84136285Sbrian  "packet filters", "show filter [in|out|dial|alive]"},
84236285Sbrian  {"hdlc", NULL, hdlc_ReportStatus, LOCAL_AUTH | LOCAL_CX,
84336285Sbrian  "HDLC errors", "show hdlc"},
84440561Sbrian  {"iface", "interface", iface_Show, LOCAL_AUTH,
84540561Sbrian  "Interface status", "show iface"},
84636285Sbrian  {"ipcp", NULL, ipcp_Show, LOCAL_AUTH,
84736285Sbrian  "IPCP status", "show ipcp"},
84847211Sbrian  {"layers", NULL, link_ShowLayers, LOCAL_AUTH | LOCAL_CX_OPT,
84947211Sbrian  "Protocol layers", "show layers"},
85036285Sbrian  {"lcp", NULL, lcp_ReportStatus, LOCAL_AUTH | LOCAL_CX,
85136285Sbrian  "LCP status", "show lcp"},
85236285Sbrian  {"link", "datalink", datalink_Show, LOCAL_AUTH | LOCAL_CX,
85336285Sbrian  "(high-level) link info", "show link"},
85436285Sbrian  {"links", NULL, bundle_ShowLinks, LOCAL_AUTH,
85536285Sbrian  "available link names", "show links"},
85636285Sbrian  {"log", NULL, log_ShowLevel, LOCAL_AUTH,
85736285Sbrian  "log levels", "show log"},
85836285Sbrian  {"mem", NULL, mbuf_Show, LOCAL_AUTH,
85936285Sbrian  "mbuf allocations", "show mem"},
86046686Sbrian  {"physical", NULL, physical_ShowStatus, LOCAL_AUTH | LOCAL_CX,
86146686Sbrian  "(low-level) link info", "show physical"},
86236285Sbrian  {"mp", "multilink", mp_ShowStatus, LOCAL_AUTH,
86336285Sbrian  "multilink setup", "show mp"},
86436285Sbrian  {"proto", NULL, ShowProtocolStats, LOCAL_AUTH | LOCAL_CX_OPT,
86536285Sbrian  "protocol summary", "show proto"},
86636285Sbrian  {"route", NULL, route_Show, LOCAL_AUTH,
86736285Sbrian  "routing table", "show route"},
86836285Sbrian  {"stopped", NULL, ShowStopped, LOCAL_AUTH | LOCAL_CX,
86936285Sbrian  "STOPPED timeout", "show stopped"},
87036285Sbrian  {"timers", NULL, ShowTimerList, LOCAL_AUTH,
87136285Sbrian  "alarm timers", "show timers"},
87228679Sbrian  {"version", NULL, ShowVersion, LOCAL_NO_AUTH | LOCAL_AUTH,
87336285Sbrian  "version string", "show version"},
87436285Sbrian  {"who", NULL, log_ShowWho, LOCAL_AUTH,
87536285Sbrian  "client list", "show who"},
87628679Sbrian  {"help", "?", HelpCommand, LOCAL_NO_AUTH | LOCAL_AUTH,
87731343Sbrian  "Display this message", "show help|? [command]", ShowCommands},
87828679Sbrian  {NULL, NULL, NULL},
8796059Samurai};
8806059Samurai
88130715Sbrianstatic struct cmdtab const *
88231343SbrianFindCommand(struct cmdtab const *cmds, const char *str, int *pmatch)
8836059Samurai{
88426516Sbrian  int nmatch;
88526516Sbrian  int len;
88628679Sbrian  struct cmdtab const *found;
8876059Samurai
88826516Sbrian  found = NULL;
88926516Sbrian  len = strlen(str);
89026516Sbrian  nmatch = 0;
8916059Samurai  while (cmds->func) {
89225566Sbrian    if (cmds->name && strncasecmp(str, cmds->name, len) == 0) {
89326516Sbrian      if (cmds->name[len] == '\0') {
89428679Sbrian	*pmatch = 1;
89528679Sbrian	return cmds;
89626516Sbrian      }
8976059Samurai      nmatch++;
8986059Samurai      found = cmds;
89928679Sbrian    } else if (cmds->alias && strncasecmp(str, cmds->alias, len) == 0) {
90026516Sbrian      if (cmds->alias[len] == '\0') {
90128679Sbrian	*pmatch = 1;
90228679Sbrian	return cmds;
90326516Sbrian      }
9046059Samurai      nmatch++;
9056059Samurai      found = cmds;
9066059Samurai    }
9076059Samurai    cmds++;
9086059Samurai  }
9096059Samurai  *pmatch = nmatch;
91026516Sbrian  return found;
9116059Samurai}
9126059Samurai
91336285Sbrianstatic const char *
91436285SbrianmkPrefix(int argc, char const *const *argv, char *tgt, int sz)
91536285Sbrian{
91636285Sbrian  int f, tlen, len;
91736285Sbrian
91836285Sbrian  tlen = 0;
91936285Sbrian  for (f = 0; f < argc && tlen < sz - 2; f++) {
92036285Sbrian    if (f)
92136285Sbrian      tgt[tlen++] = ' ';
92236285Sbrian    len = strlen(argv[f]);
92336285Sbrian    if (len > sz - tlen - 1)
92436285Sbrian      len = sz - tlen - 1;
92536285Sbrian    strncpy(tgt+tlen, argv[f], len);
92636285Sbrian    tlen += len;
92736285Sbrian  }
92836285Sbrian  tgt[tlen] = '\0';
92936285Sbrian  return tgt;
93036285Sbrian}
93136285Sbrian
93230715Sbrianstatic int
93336285SbrianFindExec(struct bundle *bundle, struct cmdtab const *cmds, int argc, int argn,
93436285Sbrian         char const *const *argv, struct prompt *prompt, struct datalink *cx)
9356059Samurai{
93628679Sbrian  struct cmdtab const *cmd;
9376059Samurai  int val = 1;
9386059Samurai  int nmatch;
93931343Sbrian  struct cmdargs arg;
94036285Sbrian  char prefix[100];
9416059Samurai
94236285Sbrian  cmd = FindCommand(cmds, argv[argn], &nmatch);
9436059Samurai  if (nmatch > 1)
94436285Sbrian    log_Printf(LogWARN, "%s: Ambiguous command\n",
94536285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix));
94636285Sbrian  else if (cmd && (!prompt || (cmd->lauth & prompt->auth))) {
94736285Sbrian    if ((cmd->lauth & LOCAL_CX) && !cx)
94836285Sbrian      /* We've got no context, but we require it */
94936285Sbrian      cx = bundle2datalink(bundle, NULL);
95036285Sbrian
95136285Sbrian    if ((cmd->lauth & LOCAL_CX) && !cx)
95236285Sbrian      log_Printf(LogWARN, "%s: No context (use the `link' command)\n",
95336285Sbrian                mkPrefix(argn+1, argv, prefix, sizeof prefix));
95436285Sbrian    else {
95536285Sbrian      if (cx && !(cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
95636285Sbrian        log_Printf(LogWARN, "%s: Redundant context (%s) ignored\n",
95736285Sbrian                  mkPrefix(argn+1, argv, prefix, sizeof prefix), cx->name);
95836285Sbrian        cx = NULL;
95936285Sbrian      }
96036285Sbrian      arg.cmdtab = cmds;
96136285Sbrian      arg.cmd = cmd;
96236285Sbrian      arg.argc = argc;
96336285Sbrian      arg.argn = argn+1;
96436285Sbrian      arg.argv = argv;
96536285Sbrian      arg.bundle = bundle;
96636285Sbrian      arg.cx = cx;
96736285Sbrian      arg.prompt = prompt;
96836285Sbrian      val = (*cmd->func) (&arg);
96936285Sbrian    }
97031343Sbrian  } else
97136285Sbrian    log_Printf(LogWARN, "%s: Invalid command\n",
97236285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix));
97326516Sbrian
97426516Sbrian  if (val == -1)
97536285Sbrian    log_Printf(LogWARN, "Usage: %s\n", cmd->syntax);
97628679Sbrian  else if (val)
97736285Sbrian    log_Printf(LogWARN, "%s: Failed %d\n",
97836285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix), val);
97926516Sbrian
98026516Sbrian  return val;
9816059Samurai}
9826059Samurai
98337009Sbrianint
98458045Sbriancommand_Expand_Interpret(char *buff, int nb, char *argv[MAXARGS], int offset)
98558045Sbrian{
98658045Sbrian  char buff2[LINE_LEN-offset];
98758045Sbrian
98858045Sbrian  InterpretArg(buff, buff2);
98958045Sbrian  strncpy(buff, buff2, LINE_LEN - offset - 1);
99058045Sbrian  buff[LINE_LEN - offset - 1] = '\0';
99158045Sbrian
99258045Sbrian  return command_Interpret(buff, nb, argv);
99358045Sbrian}
99458045Sbrian
99558045Sbrianint
99637009Sbriancommand_Interpret(char *buff, int nb, char *argv[MAXARGS])
9976059Samurai{
9986059Samurai  char *cp;
9996059Samurai
10006059Samurai  if (nb > 0) {
10016059Samurai    cp = buff + strcspn(buff, "\r\n");
10026059Samurai    if (cp)
10036059Samurai      *cp = '\0';
100455145Sbrian    return MakeArgs(buff, argv, MAXARGS, PARSE_REDUCE);
100537009Sbrian  }
100637009Sbrian  return 0;
100731121Sbrian}
10086059Samurai
100931822Sbrianstatic int
101031822Sbrianarghidden(int argc, char const *const *argv, int n)
101131822Sbrian{
101231822Sbrian  /* Is arg n of the given command to be hidden from the log ? */
101331828Sbrian
101431828Sbrian  /* set authkey xxxxx */
101531828Sbrian  /* set key xxxxx */
101631822Sbrian  if (n == 2 && !strncasecmp(argv[0], "se", 2) &&
101731822Sbrian      (!strncasecmp(argv[1], "authk", 5) || !strncasecmp(argv[1], "ke", 2)))
101831822Sbrian    return 1;
101931822Sbrian
102031828Sbrian  /* passwd xxxxx */
102131828Sbrian  if (n == 1 && !strncasecmp(argv[0], "p", 1))
102231828Sbrian    return 1;
102331828Sbrian
102436285Sbrian  /* set server port xxxxx .... */
102536285Sbrian  if (n == 3 && !strncasecmp(argv[0], "se", 2) &&
102636285Sbrian      !strncasecmp(argv[1], "se", 2))
102736285Sbrian    return 1;
102836285Sbrian
102931822Sbrian  return 0;
103031822Sbrian}
103131822Sbrian
103231121Sbrianvoid
103336285Sbriancommand_Run(struct bundle *bundle, int argc, char const *const *argv,
103437008Sbrian           struct prompt *prompt, const char *label, struct datalink *cx)
103531121Sbrian{
103631156Sbrian  if (argc > 0) {
103736285Sbrian    if (log_IsKept(LogCOMMAND)) {
103847844Sbrian      char buf[LINE_LEN];
103931156Sbrian      int f, n;
104031156Sbrian
104131156Sbrian      if (label) {
104231962Sbrian        strncpy(buf, label, sizeof buf - 3);
104331962Sbrian        buf[sizeof buf - 3] = '\0';
104431156Sbrian        strcat(buf, ": ");
104547844Sbrian        n = strlen(buf);
104647844Sbrian      } else {
104747844Sbrian        *buf = '\0';
104847844Sbrian        n = 0;
104931156Sbrian      }
105047844Sbrian      buf[sizeof buf - 1] = '\0';	/* In case we run out of room in buf */
105147844Sbrian
105231156Sbrian      for (f = 0; f < argc; f++) {
105331962Sbrian        if (n < sizeof buf - 1 && f)
105431156Sbrian          buf[n++] = ' ';
105531822Sbrian        if (arghidden(argc, argv, f))
105636285Sbrian          strncpy(buf+n, "********", sizeof buf - n - 1);
105731822Sbrian        else
105831962Sbrian          strncpy(buf+n, argv[f], sizeof buf - n - 1);
105931156Sbrian        n += strlen(buf+n);
106031156Sbrian      }
106136285Sbrian      log_Printf(LogCOMMAND, "%s\n", buf);
106231156Sbrian    }
106337008Sbrian    FindExec(bundle, Commands, argc, 0, argv, prompt, cx);
106431156Sbrian  }
10656059Samurai}
10666059Samurai
106754914Sbrianint
106836285Sbriancommand_Decode(struct bundle *bundle, char *buff, int nb, struct prompt *prompt,
106936285Sbrian              const char *label)
107031121Sbrian{
107131121Sbrian  int argc;
107237009Sbrian  char *argv[MAXARGS];
107331121Sbrian
107458045Sbrian  if ((argc = command_Expand_Interpret(buff, nb, argv, 0)) < 0)
107554914Sbrian    return 0;
107654914Sbrian
107737008Sbrian  command_Run(bundle, argc, (char const *const *)argv, prompt, label, NULL);
107854914Sbrian  return 1;
107931121Sbrian}
108031121Sbrian
10816059Samuraistatic int
108231343SbrianShowCommand(struct cmdargs const *arg)
10836059Samurai{
108436285Sbrian  if (!arg->prompt)
108536285Sbrian    log_Printf(LogWARN, "show: Cannot show without a prompt\n");
108636285Sbrian  else if (arg->argc > arg->argn)
108736285Sbrian    FindExec(arg->bundle, ShowCommands, arg->argc, arg->argn, arg->argv,
108836285Sbrian             arg->prompt, arg->cx);
10896059Samurai  else
109036285Sbrian    prompt_Printf(arg->prompt, "Use ``show ?'' to get a list.\n");
109126516Sbrian
109226516Sbrian  return 0;
10936059Samurai}
10946059Samurai
10956059Samuraistatic int
109631343SbrianTerminalCommand(struct cmdargs const *arg)
10976059Samurai{
109836285Sbrian  if (!arg->prompt) {
109936285Sbrian    log_Printf(LogWARN, "term: Need a prompt\n");
110026516Sbrian    return 1;
11016059Samurai  }
110236285Sbrian
110336285Sbrian  if (arg->cx->physical->link.lcp.fsm.state > ST_CLOSED) {
110436285Sbrian    prompt_Printf(arg->prompt, "LCP state is [%s]\n",
110536285Sbrian                  State2Nam(arg->cx->physical->link.lcp.fsm.state));
110636285Sbrian    return 1;
11076059Samurai  }
110836285Sbrian
110936285Sbrian  datalink_Up(arg->cx, 0, 0);
111036285Sbrian  prompt_TtyTermMode(arg->prompt, arg->cx);
111136285Sbrian  return 0;
11126059Samurai}
11136059Samurai
11146059Samuraistatic int
111531343SbrianQuitCommand(struct cmdargs const *arg)
11166059Samurai{
111736285Sbrian  if (!arg->prompt || prompt_IsController(arg->prompt) ||
111836285Sbrian      (arg->argc > arg->argn && !strcasecmp(arg->argv[arg->argn], "all") &&
111936285Sbrian       (arg->prompt->auth & LOCAL_AUTH)))
112036285Sbrian    Cleanup(EX_NORMAL);
112136285Sbrian  if (arg->prompt)
112236285Sbrian    prompt_Destroy(arg->prompt, 1);
112326516Sbrian
112426516Sbrian  return 0;
11256059Samurai}
11266059Samurai
11276059Samuraistatic int
112836285SbrianOpenCommand(struct cmdargs const *arg)
11296059Samurai{
113037160Sbrian  if (arg->argc == arg->argn)
113137993Sbrian    bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1);
113237160Sbrian  else if (arg->argc == arg->argn + 1) {
113337160Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp")) {
113437385Sbrian      struct datalink *cx = arg->cx ?
113537385Sbrian        arg->cx : bundle2datalink(arg->bundle, NULL);
113637385Sbrian      if (cx) {
113737385Sbrian        if (cx->physical->link.lcp.fsm.state == ST_OPENED)
113837385Sbrian          fsm_Reopen(&cx->physical->link.lcp.fsm);
113937160Sbrian        else
114037993Sbrian          bundle_Open(arg->bundle, cx->name, PHYS_ALL, 1);
114137160Sbrian      } else
114237160Sbrian        log_Printf(LogWARN, "open lcp: You must specify a link\n");
114337160Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) {
114437160Sbrian      struct fsm *fp;
11456059Samurai
114637210Sbrian      fp = &command_ChooseLink(arg)->ccp.fsm;
114737160Sbrian      if (fp->link->lcp.fsm.state != ST_OPENED)
114837160Sbrian        log_Printf(LogWARN, "open: LCP must be open before opening CCP\n");
114937160Sbrian      else if (fp->state == ST_OPENED)
115037160Sbrian        fsm_Reopen(fp);
115137160Sbrian      else {
115237160Sbrian        fp->open_mode = 0;	/* Not passive any more */
115337160Sbrian        if (fp->state == ST_STOPPED) {
115437160Sbrian          fsm_Down(fp);
115537160Sbrian          fsm_Up(fp);
115637160Sbrian        } else {
115737160Sbrian          fsm_Up(fp);
115837160Sbrian          fsm_Open(fp);
115937160Sbrian        }
116036285Sbrian      }
116137160Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ipcp")) {
116237160Sbrian      if (arg->cx)
116337160Sbrian        log_Printf(LogWARN, "open ipcp: You need not specify a link\n");
116437160Sbrian      if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED)
116537160Sbrian        fsm_Reopen(&arg->bundle->ncp.ipcp.fsm);
116637160Sbrian      else
116737993Sbrian        bundle_Open(arg->bundle, NULL, PHYS_ALL, 1);
116837160Sbrian    } else
116937160Sbrian      return -1;
117036285Sbrian  } else
117136285Sbrian    return -1;
117236285Sbrian
117326516Sbrian  return 0;
11746059Samurai}
11756059Samurai
117625067Sbrianstatic int
117736285SbrianCloseCommand(struct cmdargs const *arg)
11786059Samurai{
117937007Sbrian  if (arg->argc == arg->argn)
118037007Sbrian    bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_STAYDOWN);
118137007Sbrian  else if (arg->argc == arg->argn + 1) {
118237007Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp"))
118337007Sbrian      bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_LCP);
118437007Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "ccp") ||
118537007Sbrian             !strcasecmp(arg->argv[arg->argn], "ccp!")) {
118637007Sbrian      struct fsm *fp;
11876059Samurai
118837210Sbrian      fp = &command_ChooseLink(arg)->ccp.fsm;
118937007Sbrian      if (fp->state == ST_OPENED) {
119037007Sbrian        fsm_Close(fp);
119137007Sbrian        if (arg->argv[arg->argn][3] == '!')
119237007Sbrian          fp->open_mode = 0;		/* Stay ST_CLOSED */
119337007Sbrian        else
119437007Sbrian          fp->open_mode = OPEN_PASSIVE;	/* Wait for the peer to start */
119537007Sbrian      }
119637007Sbrian    } else
119736285Sbrian      return -1;
119836285Sbrian  } else
119936285Sbrian    return -1;
120036285Sbrian
120136285Sbrian  return 0;
12026059Samurai}
12036059Samurai
120425067Sbrianstatic int
120536285SbrianDownCommand(struct cmdargs const *arg)
120611336Samurai{
120737018Sbrian  if (arg->argc == arg->argn) {
120837018Sbrian      if (arg->cx)
120937018Sbrian        datalink_Down(arg->cx, CLOSE_STAYDOWN);
121037018Sbrian      else
121137018Sbrian        bundle_Down(arg->bundle, CLOSE_STAYDOWN);
121237018Sbrian  } else if (arg->argc == arg->argn + 1) {
121337018Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp")) {
121437018Sbrian      if (arg->cx)
121537018Sbrian        datalink_Down(arg->cx, CLOSE_LCP);
121637018Sbrian      else
121737018Sbrian        bundle_Down(arg->bundle, CLOSE_LCP);
121837018Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) {
121937018Sbrian      struct fsm *fp = arg->cx ? &arg->cx->physical->link.ccp.fsm :
122037018Sbrian                                 &arg->bundle->ncp.mp.link.ccp.fsm;
122137060Sbrian      fsm2initial(fp);
122237018Sbrian    } else
122337018Sbrian      return -1;
122436285Sbrian  } else
122536285Sbrian    return -1;
122636285Sbrian
122736285Sbrian  return 0;
122825067Sbrian}
122925067Sbrian
123025067Sbrianstatic int
123136285SbrianSetModemSpeed(struct cmdargs const *arg)
123225067Sbrian{
123336285Sbrian  long speed;
123436285Sbrian  char *end;
123511336Samurai
123636285Sbrian  if (arg->argc > arg->argn && *arg->argv[arg->argn]) {
123736285Sbrian    if (arg->argc > arg->argn+1) {
123854917Sbrian      log_Printf(LogWARN, "SetModemSpeed: Too many arguments\n");
123936285Sbrian      return -1;
124011336Samurai    }
124136285Sbrian    if (strcasecmp(arg->argv[arg->argn], "sync") == 0) {
124236285Sbrian      physical_SetSync(arg->cx->physical);
124336285Sbrian      return 0;
124436285Sbrian    }
124536285Sbrian    end = NULL;
124636285Sbrian    speed = strtol(arg->argv[arg->argn], &end, 10);
124736285Sbrian    if (*end) {
124836285Sbrian      log_Printf(LogWARN, "SetModemSpeed: Bad argument \"%s\"",
124936285Sbrian                arg->argv[arg->argn]);
125036285Sbrian      return -1;
125136285Sbrian    }
125236285Sbrian    if (physical_SetSpeed(arg->cx->physical, speed))
125336285Sbrian      return 0;
125436285Sbrian    log_Printf(LogWARN, "%s: Invalid speed\n", arg->argv[arg->argn]);
125536285Sbrian  } else
125636285Sbrian    log_Printf(LogWARN, "SetModemSpeed: No speed specified\n");
125724939Sbrian
125826516Sbrian  return -1;
125911336Samurai}
126011336Samurai
126125067Sbrianstatic int
126231343SbrianSetStoppedTimeout(struct cmdargs const *arg)
126328327Sbrian{
126436285Sbrian  struct link *l = &arg->cx->physical->link;
126536285Sbrian
126636285Sbrian  l->lcp.fsm.StoppedTimer.load = 0;
126736285Sbrian  l->ccp.fsm.StoppedTimer.load = 0;
126836285Sbrian  if (arg->argc <= arg->argn+2) {
126936285Sbrian    if (arg->argc > arg->argn) {
127036285Sbrian      l->lcp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn]) * SECTICKS;
127136285Sbrian      if (arg->argc > arg->argn+1)
127236285Sbrian        l->ccp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn+1]) * SECTICKS;
127328461Sbrian    }
127428327Sbrian    return 0;
127528327Sbrian  }
127628327Sbrian  return -1;
127728327Sbrian}
127828327Sbrian
127928327Sbrianstatic int
128031343SbrianSetServer(struct cmdargs const *arg)
128126940Sbrian{
128226940Sbrian  int res = -1;
128326940Sbrian
128436285Sbrian  if (arg->argc > arg->argn && arg->argc < arg->argn+4) {
128531081Sbrian    const char *port, *passwd, *mask;
128653125Sbrian    int mlen;
128731081Sbrian
128831081Sbrian    /* What's what ? */
128936285Sbrian    port = arg->argv[arg->argn];
129036285Sbrian    if (arg->argc == arg->argn + 2) {
129136285Sbrian      passwd = arg->argv[arg->argn+1];
129236285Sbrian      mask = NULL;
129336285Sbrian    } else if (arg->argc == arg->argn + 3) {
129436285Sbrian      passwd = arg->argv[arg->argn+1];
129536285Sbrian      mask = arg->argv[arg->argn+2];
129653125Sbrian      mlen = strlen(mask);
129753125Sbrian      if (mlen == 0 || mlen > 4 || strspn(mask, "01234567") != mlen ||
129853125Sbrian          (mlen == 4 && *mask != '0')) {
129953125Sbrian        log_Printf(LogWARN, "%s %s: %s: Invalid mask\n",
130053125Sbrian                   arg->argv[arg->argn - 2], arg->argv[arg->argn - 1], mask);
130131081Sbrian        return -1;
130253125Sbrian      }
130371764Sbrian    } else if (arg->argc != arg->argn + 1)
130471764Sbrian      return -1;
130571764Sbrian    else if (strcasecmp(port, "none") == 0) {
130671657Sbrian      if (server_Clear(arg->bundle))
130771657Sbrian        log_Printf(LogPHASE, "Disabled server socket\n");
130871657Sbrian      return 0;
130971657Sbrian    } else if (strcasecmp(port, "open") == 0) {
131071657Sbrian      switch (server_Reopen(arg->bundle)) {
131171657Sbrian        case SERVER_OK:
131271657Sbrian          return 0;
131371657Sbrian        case SERVER_FAILED:
131471764Sbrian          log_Printf(LogWARN, "Failed to reopen server port\n");
131571657Sbrian          return 1;
131671657Sbrian        case SERVER_UNSET:
131771764Sbrian          log_Printf(LogWARN, "Cannot reopen unset server socket\n");
131871657Sbrian          return 1;
131971657Sbrian        default:
132071657Sbrian          break;
132171657Sbrian      }
132271657Sbrian      return -1;
132371657Sbrian    } else if (strcasecmp(port, "closed") == 0) {
132436285Sbrian      if (server_Close(arg->bundle))
132571657Sbrian        log_Printf(LogPHASE, "Closed server socket\n");
132671657Sbrian      else
132771657Sbrian        log_Printf(LogWARN, "Server socket not open\n");
132871657Sbrian
132936285Sbrian      return 0;
133031081Sbrian    } else
133136285Sbrian      return -1;
133231081Sbrian
133371657Sbrian    strncpy(server.cfg.passwd, passwd, sizeof server.cfg.passwd - 1);
133471657Sbrian    server.cfg.passwd[sizeof server.cfg.passwd - 1] = '\0';
133531081Sbrian
133636285Sbrian    if (*port == '/') {
133731081Sbrian      mode_t imask;
133836285Sbrian      char *ptr, name[LINE_LEN + 12];
133928679Sbrian
134053125Sbrian      if (mask == NULL)
134131081Sbrian        imask = (mode_t)-1;
134253125Sbrian      else for (imask = mlen = 0; mask[mlen]; mlen++)
134353125Sbrian        imask = (imask * 8) + mask[mlen] - '0';
134436285Sbrian
134536285Sbrian      ptr = strstr(port, "%d");
134636285Sbrian      if (ptr) {
134736285Sbrian        snprintf(name, sizeof name, "%.*s%d%s",
134837210Sbrian                 (int)(ptr - port), port, arg->bundle->unit, ptr + 2);
134936285Sbrian        port = name;
135036285Sbrian      }
135136285Sbrian      res = server_LocalOpen(arg->bundle, port, imask);
135227346Sbrian    } else {
135336285Sbrian      int iport, add = 0;
135428679Sbrian
135531081Sbrian      if (mask != NULL)
135631081Sbrian        return -1;
135728679Sbrian
135836285Sbrian      if (*port == '+') {
135936285Sbrian        port++;
136036285Sbrian        add = 1;
136136285Sbrian      }
136231081Sbrian      if (strspn(port, "0123456789") != strlen(port)) {
136331081Sbrian        struct servent *s;
136431081Sbrian
136531081Sbrian        if ((s = getservbyname(port, "tcp")) == NULL) {
136631081Sbrian	  iport = 0;
136736285Sbrian	  log_Printf(LogWARN, "%s: Invalid port or service\n", port);
136828679Sbrian	} else
136931081Sbrian	  iport = ntohs(s->s_port);
137027346Sbrian      } else
137131081Sbrian        iport = atoi(port);
137236285Sbrian
137336285Sbrian      if (iport) {
137436285Sbrian        if (add)
137536285Sbrian          iport += arg->bundle->unit;
137636285Sbrian        res = server_TcpOpen(arg->bundle, iport);
137736285Sbrian      } else
137836285Sbrian        res = -1;
137927346Sbrian    }
138031081Sbrian  }
138126940Sbrian
138226940Sbrian  return res;
138326940Sbrian}
138426940Sbrian
138526940Sbrianstatic int
138631343SbrianSetEscape(struct cmdargs const *arg)
13876059Samurai{
13886059Samurai  int code;
138936285Sbrian  int argc = arg->argc - arg->argn;
139036285Sbrian  char const *const *argv = arg->argv + arg->argn;
13916059Samurai
13926059Samurai  for (code = 0; code < 33; code++)
139336285Sbrian    arg->cx->physical->async.cfg.EscMap[code] = 0;
139431343Sbrian
13956059Samurai  while (argc-- > 0) {
13966059Samurai    sscanf(*argv++, "%x", &code);
13976059Samurai    code &= 0xff;
139836285Sbrian    arg->cx->physical->async.cfg.EscMap[code >> 3] |= (1 << (code & 7));
139936285Sbrian    arg->cx->physical->async.cfg.EscMap[32] = 1;
14006059Samurai  }
140126516Sbrian  return 0;
14026059Samurai}
14036059Samurai
14046059Samuraistatic int
140531343SbrianSetInterfaceAddr(struct cmdargs const *arg)
14066059Samurai{
140736285Sbrian  struct ipcp *ipcp = &arg->bundle->ncp.ipcp;
140832267Sbrian  const char *hisaddr;
140932267Sbrian
141040561Sbrian  if (arg->argc > arg->argn + 4)
141140561Sbrian    return -1;
141240561Sbrian
141332267Sbrian  hisaddr = NULL;
141444874Sbrian  memset(&ipcp->cfg.my_range, '\0', sizeof ipcp->cfg.my_range);
141544874Sbrian  memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
141636285Sbrian  ipcp->cfg.HaveTriggerAddress = 0;
141736285Sbrian  ipcp->cfg.netmask.s_addr = INADDR_ANY;
141836285Sbrian  iplist_reset(&ipcp->cfg.peer_list);
141928394Sbrian
142036285Sbrian  if (arg->argc > arg->argn) {
142143313Sbrian    if (!ParseAddr(ipcp, arg->argv[arg->argn],
142236285Sbrian                   &ipcp->cfg.my_range.ipaddr, &ipcp->cfg.my_range.mask,
142336285Sbrian                   &ipcp->cfg.my_range.width))
142428679Sbrian      return 1;
142536285Sbrian    if (arg->argc > arg->argn+1) {
142636285Sbrian      hisaddr = arg->argv[arg->argn+1];
142736285Sbrian      if (arg->argc > arg->argn+2) {
142844455Sbrian        ipcp->ifmask = ipcp->cfg.netmask = GetIpAddr(arg->argv[arg->argn+2]);
142936285Sbrian	if (arg->argc > arg->argn+3) {
143036285Sbrian	  ipcp->cfg.TriggerAddress = GetIpAddr(arg->argv[arg->argn+3]);
143136285Sbrian	  ipcp->cfg.HaveTriggerAddress = 1;
14329440Samurai	}
14336059Samurai      }
14346059Samurai    }
14356059Samurai  }
143628394Sbrian
143740561Sbrian  /* 0.0.0.0 means any address (0 bits) */
143836285Sbrian  if (ipcp->cfg.my_range.ipaddr.s_addr == INADDR_ANY) {
143936285Sbrian    ipcp->cfg.my_range.mask.s_addr = INADDR_ANY;
144036285Sbrian    ipcp->cfg.my_range.width = 0;
14416059Samurai  }
144236285Sbrian  ipcp->my_ip.s_addr = ipcp->cfg.my_range.ipaddr.s_addr;
144347648Sbrian  bundle_AdjustFilters(arg->bundle, &ipcp->my_ip, NULL);
144436285Sbrian
144536285Sbrian  if (hisaddr && !ipcp_UseHisaddr(arg->bundle, hisaddr,
144636928Sbrian                                  arg->bundle->phys_type.all & PHYS_AUTO))
144732267Sbrian    return 4;
144831121Sbrian
144926516Sbrian  return 0;
14506059Samurai}
14516059Samurai
145218752Sjkhstatic int
145344305SbrianSetRetry(int argc, char const *const *argv, u_int *timeout, u_int *maxreq,
145444305Sbrian          u_int *maxtrm, int def)
145544305Sbrian{
145644305Sbrian  if (argc == 0) {
145744305Sbrian    *timeout = DEF_FSMRETRY;
145844305Sbrian    *maxreq = def;
145944305Sbrian    if (maxtrm != NULL)
146044305Sbrian      *maxtrm = def;
146144305Sbrian  } else {
146244305Sbrian    long l = atol(argv[0]);
146344305Sbrian
146444305Sbrian    if (l < MIN_FSMRETRY) {
146544305Sbrian      log_Printf(LogWARN, "%ld: Invalid FSM retry period - min %d\n",
146644305Sbrian                 l, MIN_FSMRETRY);
146744305Sbrian      return 1;
146844305Sbrian    } else
146944305Sbrian      *timeout = l;
147044305Sbrian
147144305Sbrian    if (argc > 1) {
147244305Sbrian      l = atol(argv[1]);
147344305Sbrian      if (l < 1) {
147444305Sbrian        log_Printf(LogWARN, "%ld: Invalid FSM REQ tries - changed to 1\n", l);
147544305Sbrian        l = 1;
147644305Sbrian      }
147744305Sbrian      *maxreq = l;
147844305Sbrian
147944305Sbrian      if (argc > 2 && maxtrm != NULL) {
148044305Sbrian        l = atol(argv[2]);
148144305Sbrian        if (l < 1) {
148244305Sbrian          log_Printf(LogWARN, "%ld: Invalid FSM TRM tries - changed to 1\n", l);
148344305Sbrian          l = 1;
148444305Sbrian        }
148544305Sbrian        *maxtrm = l;
148644305Sbrian      }
148744305Sbrian    }
148844305Sbrian  }
148944305Sbrian
149044305Sbrian  return 0;
149144305Sbrian}
149244305Sbrian
149344305Sbrianstatic int
149431343SbrianSetVariable(struct cmdargs const *arg)
14956059Samurai{
149637210Sbrian  long long_val, param = (long)arg->cmd->args;
149779119Sbrian  int mode, dummyint, f, first, res;
149878410Sbrian  u_short *change;
149931343Sbrian  const char *argp;
150036285Sbrian  struct datalink *cx = arg->cx;	/* LOCAL_CX uses this */
150136285Sbrian  struct link *l = command_ChooseLink(arg);	/* LOCAL_CX_OPT uses this */
150236285Sbrian  struct in_addr dummyaddr, *addr;
15036059Samurai
150436285Sbrian  if (arg->argc > arg->argn)
150536285Sbrian    argp = arg->argv[arg->argn];
150626551Sbrian  else
150731343Sbrian    argp = "";
150826551Sbrian
150979119Sbrian  res = 0;
151079119Sbrian
151136285Sbrian  if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
151236285Sbrian    log_Printf(LogWARN, "set %s: No context (use the `link' command)\n",
151336285Sbrian              arg->cmd->name);
151436285Sbrian    return 1;
151536285Sbrian  } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
151636285Sbrian    log_Printf(LogWARN, "set %s: Redundant context (%s) ignored\n",
151736285Sbrian              arg->cmd->name, cx->name);
151836285Sbrian    cx = NULL;
151936285Sbrian  }
152036285Sbrian
152126551Sbrian  switch (param) {
152228679Sbrian  case VAR_AUTHKEY:
152350139Sbrian    strncpy(arg->bundle->cfg.auth.key, argp,
152450139Sbrian            sizeof arg->bundle->cfg.auth.key - 1);
152550139Sbrian    arg->bundle->cfg.auth.key[sizeof arg->bundle->cfg.auth.key - 1] = '\0';
152628679Sbrian    break;
152737210Sbrian
152828679Sbrian  case VAR_AUTHNAME:
152940622Sbrian    switch (bundle_Phase(arg->bundle)) {
153058880Sbrian      default:
153158880Sbrian        log_Printf(LogWARN, "Altering authname while at phase %s\n",
153258880Sbrian                   bundle_PhaseName(arg->bundle));
153358880Sbrian        /* drop through */
153440622Sbrian      case PHASE_DEAD:
153540622Sbrian      case PHASE_ESTABLISH:
153640622Sbrian        strncpy(arg->bundle->cfg.auth.name, argp,
153740622Sbrian                sizeof arg->bundle->cfg.auth.name - 1);
153840622Sbrian        arg->bundle->cfg.auth.name[sizeof arg->bundle->cfg.auth.name-1] = '\0';
153940622Sbrian        break;
154036285Sbrian    }
154128679Sbrian    break;
154237210Sbrian
154336285Sbrian  case VAR_AUTOLOAD:
154449434Sbrian    if (arg->argc == arg->argn + 3) {
154549434Sbrian      int v1, v2, v3;
154649434Sbrian      char *end;
154749434Sbrian
154849434Sbrian      v1 = strtol(arg->argv[arg->argn], &end, 0);
154949434Sbrian      if (v1 < 0 || *end) {
155049434Sbrian        log_Printf(LogWARN, "autoload: %s: Invalid min percentage\n",
155149434Sbrian                   arg->argv[arg->argn]);
155279119Sbrian        res = 1;
155379119Sbrian        break;
155436285Sbrian      }
155549434Sbrian
155649434Sbrian      v2 = strtol(arg->argv[arg->argn + 1], &end, 0);
155749434Sbrian      if (v2 < 0 || *end) {
155849434Sbrian        log_Printf(LogWARN, "autoload: %s: Invalid max percentage\n",
155949434Sbrian                   arg->argv[arg->argn + 1]);
156079119Sbrian        res = 1;
156179119Sbrian        break;
156249434Sbrian      }
156349434Sbrian      if (v2 < v1) {
156449434Sbrian        v3 = v1;
156549434Sbrian        v1 = v2;
156649434Sbrian        v2 = v3;
156749434Sbrian      }
156849434Sbrian
156949434Sbrian      v3 = strtol(arg->argv[arg->argn + 2], &end, 0);
157049434Sbrian      if (v3 <= 0 || *end) {
157149434Sbrian        log_Printf(LogWARN, "autoload: %s: Invalid throughput period\n",
157249434Sbrian                   arg->argv[arg->argn + 2]);
157379119Sbrian        res = 1;
157479119Sbrian        break;
157549434Sbrian      }
157649434Sbrian
157749434Sbrian      arg->bundle->ncp.mp.cfg.autoload.min = v1;
157849434Sbrian      arg->bundle->ncp.mp.cfg.autoload.max = v2;
157949434Sbrian      arg->bundle->ncp.mp.cfg.autoload.period = v3;
158049434Sbrian      mp_RestartAutoloadTimer(&arg->bundle->ncp.mp);
158136285Sbrian    } else {
158279119Sbrian      log_Printf(LogWARN, "Set autoload requires three arguments\n");
158379119Sbrian      res = 1;
158436285Sbrian    }
158536285Sbrian    break;
158637210Sbrian
158728679Sbrian  case VAR_DIAL:
158836285Sbrian    strncpy(cx->cfg.script.dial, argp, sizeof cx->cfg.script.dial - 1);
158936285Sbrian    cx->cfg.script.dial[sizeof cx->cfg.script.dial - 1] = '\0';
159028679Sbrian    break;
159137210Sbrian
159228679Sbrian  case VAR_LOGIN:
159336285Sbrian    strncpy(cx->cfg.script.login, argp, sizeof cx->cfg.script.login - 1);
159436285Sbrian    cx->cfg.script.login[sizeof cx->cfg.script.login - 1] = '\0';
159528679Sbrian    break;
159637210Sbrian
159736285Sbrian  case VAR_WINSIZE:
159836285Sbrian    if (arg->argc > arg->argn) {
159936285Sbrian      l->ccp.cfg.deflate.out.winsize = atoi(arg->argv[arg->argn]);
160036285Sbrian      if (l->ccp.cfg.deflate.out.winsize < 8 ||
160136285Sbrian          l->ccp.cfg.deflate.out.winsize > 15) {
160236285Sbrian          log_Printf(LogWARN, "%d: Invalid outgoing window size\n",
160336285Sbrian                    l->ccp.cfg.deflate.out.winsize);
160436285Sbrian          l->ccp.cfg.deflate.out.winsize = 15;
160536285Sbrian      }
160636285Sbrian      if (arg->argc > arg->argn+1) {
160736285Sbrian        l->ccp.cfg.deflate.in.winsize = atoi(arg->argv[arg->argn+1]);
160836285Sbrian        if (l->ccp.cfg.deflate.in.winsize < 8 ||
160936285Sbrian            l->ccp.cfg.deflate.in.winsize > 15) {
161036285Sbrian            log_Printf(LogWARN, "%d: Invalid incoming window size\n",
161136285Sbrian                      l->ccp.cfg.deflate.in.winsize);
161236285Sbrian            l->ccp.cfg.deflate.in.winsize = 15;
161336285Sbrian        }
161436285Sbrian      } else
161536285Sbrian        l->ccp.cfg.deflate.in.winsize = 0;
161636285Sbrian    } else {
161779119Sbrian      log_Printf(LogWARN, "No window size specified\n");
161879119Sbrian      res = 1;
161936285Sbrian    }
162036285Sbrian    break;
162137210Sbrian
162267910Sbrian#ifdef HAVE_DES
162378411Sbrian  case VAR_MPPE:
162479119Sbrian    if (arg->argc > arg->argn + 2) {
162579119Sbrian      res = -1;
162679119Sbrian      break;
162779119Sbrian    }
162878411Sbrian
162978411Sbrian    if (arg->argc == arg->argn) {
163078411Sbrian      l->ccp.cfg.mppe.keybits = 0;
163178411Sbrian      l->ccp.cfg.mppe.state = MPPE_ANYSTATE;
163278411Sbrian      l->ccp.cfg.mppe.required = 0;
163378411Sbrian      break;
163478411Sbrian    }
163578411Sbrian
163678411Sbrian    if (!strcmp(argp, "*"))
163778411Sbrian      long_val = 0;
163878411Sbrian    else {
163978411Sbrian      long_val = atol(argp);
164078411Sbrian      if (long_val != 40 && long_val != 56 && long_val != 128) {
164178411Sbrian        log_Printf(LogWARN, "%s: Invalid bits value\n", argp);
164279119Sbrian        res = -1;
164379119Sbrian        break;
164467910Sbrian      }
164567910Sbrian    }
164678411Sbrian
164778411Sbrian    if (arg->argc == arg->argn + 2) {
164878411Sbrian      if (!strcmp(arg->argv[arg->argn + 1], "*"))
164978411Sbrian        l->ccp.cfg.mppe.state = MPPE_ANYSTATE;
165078411Sbrian      else if (!strcasecmp(arg->argv[arg->argn + 1], "stateless"))
165178411Sbrian        l->ccp.cfg.mppe.state = MPPE_STATELESS;
165279370Sbrian      else if (!strcasecmp(arg->argv[arg->argn + 1], "stateful"))
165378411Sbrian        l->ccp.cfg.mppe.state = MPPE_STATEFUL;
165478411Sbrian      else {
165578411Sbrian        log_Printf(LogWARN, "%s: Invalid state value\n",
165678411Sbrian                   arg->argv[arg->argn + 1]);
165779119Sbrian        res = -1;
165879119Sbrian        break;
165978411Sbrian      }
166078411Sbrian    } else
166178411Sbrian      l->ccp.cfg.mppe.state = MPPE_ANYSTATE;
166278411Sbrian    l->ccp.cfg.mppe.keybits = long_val;
166378411Sbrian    l->ccp.cfg.mppe.required = 1;
166467910Sbrian    break;
166567910Sbrian#endif
166667910Sbrian
166728679Sbrian  case VAR_DEVICE:
166836285Sbrian    physical_SetDeviceList(cx->physical, arg->argc - arg->argn,
166936285Sbrian                           arg->argv + arg->argn);
167036285Sbrian    break;
167137210Sbrian
167236285Sbrian  case VAR_ACCMAP:
167336285Sbrian    if (arg->argc > arg->argn) {
167437210Sbrian      u_long ulong_val;
167536285Sbrian      sscanf(argp, "%lx", &ulong_val);
167637210Sbrian      cx->physical->link.lcp.cfg.accmap = (u_int32_t)ulong_val;
167736285Sbrian    } else {
167879119Sbrian      log_Printf(LogWARN, "No accmap specified\n");
167979119Sbrian      res = 1;
168036285Sbrian    }
168136285Sbrian    break;
168237210Sbrian
168336285Sbrian  case VAR_MODE:
168436285Sbrian    mode = Nam2mode(argp);
168536285Sbrian    if (mode == PHYS_NONE || mode == PHYS_ALL) {
168636285Sbrian      log_Printf(LogWARN, "%s: Invalid mode\n", argp);
168779119Sbrian      res = -1;
168879119Sbrian      break;
168936285Sbrian    }
169036285Sbrian    bundle_SetMode(arg->bundle, cx, mode);
169136285Sbrian    break;
169237210Sbrian
169336285Sbrian  case VAR_MRRU:
169440622Sbrian    switch (bundle_Phase(arg->bundle)) {
169540622Sbrian      case PHASE_DEAD:
169640622Sbrian        break;
169740622Sbrian      case PHASE_ESTABLISH:
169840622Sbrian        /* Make sure none of our links are DATALINK_LCP or greater */
169940622Sbrian        if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) {
170040622Sbrian          log_Printf(LogWARN, "mrru: Only changable before LCP negotiations\n");
170179119Sbrian          res = 1;
170279119Sbrian          break;
170340622Sbrian        }
170440622Sbrian        break;
170540622Sbrian      default:
170640622Sbrian        log_Printf(LogWARN, "mrru: Only changable at phase DEAD/ESTABLISH\n");
170779119Sbrian        res = 1;
170879119Sbrian        break;
170929696Sbrian    }
171079119Sbrian    if (res != 0)
171179119Sbrian      break;
171237210Sbrian    long_val = atol(argp);
171337210Sbrian    if (long_val && long_val < MIN_MRU) {
171437210Sbrian      log_Printf(LogWARN, "MRRU %ld: too small - min %d\n", long_val, MIN_MRU);
171579119Sbrian      res = 1;
171679119Sbrian      break;
171737210Sbrian    } else if (long_val > MAX_MRU) {
171837210Sbrian      log_Printf(LogWARN, "MRRU %ld: too big - max %d\n", long_val, MAX_MRU);
171979119Sbrian      res = 1;
172079119Sbrian      break;
172137210Sbrian    } else
172237210Sbrian      arg->bundle->ncp.mp.cfg.mrru = long_val;
172328679Sbrian    break;
172437210Sbrian
172536285Sbrian  case VAR_MRU:
172679163Sbrian    long_val = 0;	/* silence gcc */
172779163Sbrian    change = NULL;	/* silence gcc */
172878410Sbrian    switch(arg->argc - arg->argn) {
172978410Sbrian    case 1:
173079119Sbrian      if (argp[strspn(argp, "0123456789")] != '\0') {
173179119Sbrian        res = -1;
173279119Sbrian        break;
173379119Sbrian      }
173479119Sbrian      /*FALLTHRU*/
173578410Sbrian    case 0:
173678410Sbrian      long_val = atol(argp);
173778410Sbrian      change = &l->lcp.cfg.mru;
173878410Sbrian      if (long_val > l->lcp.cfg.max_mru) {
173978410Sbrian        log_Printf(LogWARN, "MRU %ld: too large - max set to %d\n", long_val,
174078410Sbrian                   l->lcp.cfg.max_mru);
174179119Sbrian        res = 1;
174279119Sbrian        break;
174378410Sbrian      }
174478410Sbrian      break;
174578410Sbrian    case 2:
174679119Sbrian      if (strcasecmp(argp, "max") && strcasecmp(argp, "maximum")) {
174779119Sbrian        res = -1;
174879119Sbrian        break;
174979119Sbrian      }
175078410Sbrian      long_val = atol(arg->argv[arg->argn + 1]);
175178410Sbrian      change = &l->lcp.cfg.max_mru;
175278410Sbrian      if (long_val > MAX_MRU) {
175378410Sbrian        log_Printf(LogWARN, "MRU %ld: too large - maximum is %d\n", long_val,
175478410Sbrian                   MAX_MRU);
175579119Sbrian        res = 1;
175679119Sbrian        break;
175778410Sbrian      }
175878410Sbrian      break;
175978410Sbrian    default:
176079119Sbrian      res = -1;
176179119Sbrian      break;
176278410Sbrian    }
176379119Sbrian    if (res != 0)
176479119Sbrian      break;
176578410Sbrian
176637210Sbrian    if (long_val == 0)
176780385Sbrian      *change = 0;
176837210Sbrian    else if (long_val < MIN_MRU) {
176937210Sbrian      log_Printf(LogWARN, "MRU %ld: too small - min %d\n", long_val, MIN_MRU);
177079119Sbrian      res = 1;
177179119Sbrian      break;
177237210Sbrian    } else if (long_val > MAX_MRU) {
177337210Sbrian      log_Printf(LogWARN, "MRU %ld: too big - max %d\n", long_val, MAX_MRU);
177479119Sbrian      res = 1;
177579119Sbrian      break;
177637210Sbrian    } else
177778410Sbrian      *change = long_val;
177878410Sbrian    if (l->lcp.cfg.mru > *change)
177978410Sbrian      l->lcp.cfg.mru = *change;
178028679Sbrian    break;
178137210Sbrian
178236285Sbrian  case VAR_MTU:
178379163Sbrian    long_val = 0;	/* silence gcc */
178479163Sbrian    change = NULL;	/* silence gcc */
178578410Sbrian    switch(arg->argc - arg->argn) {
178678410Sbrian    case 1:
178779119Sbrian      if (argp[strspn(argp, "0123456789")] != '\0') {
178879119Sbrian        res = -1;
178979119Sbrian        break;
179079119Sbrian      }
179179119Sbrian      /*FALLTHRU*/
179278410Sbrian    case 0:
179378410Sbrian      long_val = atol(argp);
179478410Sbrian      change = &l->lcp.cfg.mtu;
179578410Sbrian      if (long_val > l->lcp.cfg.max_mtu) {
179678410Sbrian        log_Printf(LogWARN, "MTU %ld: too large - max set to %d\n", long_val,
179778410Sbrian                   l->lcp.cfg.max_mtu);
179879119Sbrian        res = 1;
179979119Sbrian        break;
180078410Sbrian      }
180178410Sbrian      break;
180278410Sbrian    case 2:
180379119Sbrian      if (strcasecmp(argp, "max") && strcasecmp(argp, "maximum")) {
180479119Sbrian        res = -1;
180579119Sbrian        break;
180679119Sbrian      }
180778410Sbrian      long_val = atol(arg->argv[arg->argn + 1]);
180878410Sbrian      change = &l->lcp.cfg.max_mtu;
180978410Sbrian      if (long_val > MAX_MTU) {
181078410Sbrian        log_Printf(LogWARN, "MTU %ld: too large - maximum is %d\n", long_val,
181178410Sbrian                   MAX_MTU);
181279119Sbrian        res = 1;
181379119Sbrian        break;
181478410Sbrian      }
181578410Sbrian      break;
181678410Sbrian    default:
181779119Sbrian      res = -1;
181879119Sbrian      break;
181978410Sbrian    }
182078410Sbrian
182179119Sbrian    if (res != 0)
182279119Sbrian      break;
182379119Sbrian
182437210Sbrian    if (long_val && long_val < MIN_MTU) {
182537210Sbrian      log_Printf(LogWARN, "MTU %ld: too small - min %d\n", long_val, MIN_MTU);
182679119Sbrian      res = 1;
182779119Sbrian      break;
182837210Sbrian    } else if (long_val > MAX_MTU) {
182937210Sbrian      log_Printf(LogWARN, "MTU %ld: too big - max %d\n", long_val, MAX_MTU);
183079119Sbrian      res = 1;
183179119Sbrian      break;
183237210Sbrian    } else
183378410Sbrian      *change = long_val;
183478410Sbrian    if (l->lcp.cfg.mtu > *change)
183578410Sbrian      l->lcp.cfg.mtu = *change;
183636285Sbrian    break;
183737210Sbrian
183836285Sbrian  case VAR_OPENMODE:
183936285Sbrian    if (strcasecmp(argp, "active") == 0)
184036285Sbrian      cx->physical->link.lcp.cfg.openmode = arg->argc > arg->argn+1 ?
184136285Sbrian        atoi(arg->argv[arg->argn+1]) : 1;
184236285Sbrian    else if (strcasecmp(argp, "passive") == 0)
184336285Sbrian      cx->physical->link.lcp.cfg.openmode = OPEN_PASSIVE;
184436285Sbrian    else {
184579119Sbrian      log_Printf(LogWARN, "%s: Invalid openmode\n", argp);
184679119Sbrian      res = 1;
184736285Sbrian    }
184836285Sbrian    break;
184937210Sbrian
185028679Sbrian  case VAR_PHONE:
185136285Sbrian    strncpy(cx->cfg.phone.list, argp, sizeof cx->cfg.phone.list - 1);
185236285Sbrian    cx->cfg.phone.list[sizeof cx->cfg.phone.list - 1] = '\0';
185338174Sbrian    cx->phone.alt = cx->phone.next = NULL;
185428679Sbrian    break;
185537210Sbrian
185628679Sbrian  case VAR_HANGUP:
185736285Sbrian    strncpy(cx->cfg.script.hangup, argp, sizeof cx->cfg.script.hangup - 1);
185836285Sbrian    cx->cfg.script.hangup[sizeof cx->cfg.script.hangup - 1] = '\0';
185928679Sbrian    break;
186037210Sbrian
186161534Sbrian  case VAR_IFQUEUE:
186261534Sbrian    long_val = atol(argp);
186361534Sbrian    arg->bundle->cfg.ifqueue = long_val < 0 ? 0 : long_val;
186461534Sbrian    break;
186561534Sbrian
186652488Sbrian  case VAR_LOGOUT:
186752488Sbrian    strncpy(cx->cfg.script.logout, argp, sizeof cx->cfg.script.logout - 1);
186852488Sbrian    cx->cfg.script.logout[sizeof cx->cfg.script.logout - 1] = '\0';
186952488Sbrian    break;
187052488Sbrian
187136285Sbrian  case VAR_IDLETIMEOUT:
187279119Sbrian    if (arg->argc > arg->argn+2) {
187379119Sbrian      log_Printf(LogWARN, "Too many idle timeout values\n");
187479119Sbrian      res = 1;
187579119Sbrian    } else if (arg->argc == arg->argn) {
187679119Sbrian      log_Printf(LogWARN, "Too few idle timeout values\n");
187779119Sbrian      res = 1;
187879119Sbrian    } else {
187949978Sbrian      int timeout, min;
188049978Sbrian
188149978Sbrian      timeout = atoi(argp);
188249978Sbrian      min = arg->argc == arg->argn + 2 ? atoi(arg->argv[arg->argn + 1]) : -1;
188349978Sbrian      bundle_SetIdleTimer(arg->bundle, timeout, min);
188449978Sbrian    }
188529549Sbrian    break;
188637210Sbrian
188736285Sbrian  case VAR_LQRPERIOD:
188837210Sbrian    long_val = atol(argp);
188937210Sbrian    if (long_val < MIN_LQRPERIOD) {
189037210Sbrian      log_Printf(LogWARN, "%ld: Invalid lqr period - min %d\n",
189137210Sbrian                 long_val, MIN_LQRPERIOD);
189279119Sbrian      res = 1;
189336285Sbrian    } else
189437210Sbrian      l->lcp.cfg.lqrperiod = long_val;
189536285Sbrian    break;
189637210Sbrian
189736285Sbrian  case VAR_LCPRETRY:
189879119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
189979119Sbrian                   &cx->physical->link.lcp.cfg.fsm.timeout,
190079119Sbrian                   &cx->physical->link.lcp.cfg.fsm.maxreq,
190179119Sbrian                   &cx->physical->link.lcp.cfg.fsm.maxtrm, DEF_FSMTRIES);
190236285Sbrian    break;
190337210Sbrian
190436285Sbrian  case VAR_CHAPRETRY:
190579119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
190679119Sbrian                   &cx->chap.auth.cfg.fsm.timeout,
190779119Sbrian                   &cx->chap.auth.cfg.fsm.maxreq, NULL, DEF_FSMAUTHTRIES);
190836285Sbrian    break;
190937210Sbrian
191036285Sbrian  case VAR_PAPRETRY:
191179119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
191279119Sbrian                   &cx->pap.cfg.fsm.timeout, &cx->pap.cfg.fsm.maxreq,
191379119Sbrian                   NULL, DEF_FSMAUTHTRIES);
191436285Sbrian    break;
191537210Sbrian
191636285Sbrian  case VAR_CCPRETRY:
191779119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
191879119Sbrian                   &l->ccp.cfg.fsm.timeout, &l->ccp.cfg.fsm.maxreq,
191979119Sbrian                   &l->ccp.cfg.fsm.maxtrm, DEF_FSMTRIES);
192036285Sbrian    break;
192137210Sbrian
192236285Sbrian  case VAR_IPCPRETRY:
192379119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
192479119Sbrian                   &arg->bundle->ncp.ipcp.cfg.fsm.timeout,
192579119Sbrian                   &arg->bundle->ncp.ipcp.cfg.fsm.maxreq,
192679119Sbrian                   &arg->bundle->ncp.ipcp.cfg.fsm.maxtrm, DEF_FSMTRIES);
192736285Sbrian    break;
192837210Sbrian
192936285Sbrian  case VAR_NBNS:
193036285Sbrian  case VAR_DNS:
193158044Sbrian    if (param == VAR_DNS) {
193236285Sbrian      addr = arg->bundle->ncp.ipcp.cfg.ns.dns;
193358044Sbrian      addr[0].s_addr = addr[1].s_addr = INADDR_NONE;
193458044Sbrian    } else {
193536285Sbrian      addr = arg->bundle->ncp.ipcp.cfg.ns.nbns;
193658044Sbrian      addr[0].s_addr = addr[1].s_addr = INADDR_ANY;
193758044Sbrian    }
193836285Sbrian
193936285Sbrian    if (arg->argc > arg->argn) {
194043313Sbrian      ParseAddr(&arg->bundle->ncp.ipcp, arg->argv[arg->argn],
194136285Sbrian                addr, &dummyaddr, &dummyint);
194236285Sbrian      if (arg->argc > arg->argn+1)
194343313Sbrian        ParseAddr(&arg->bundle->ncp.ipcp, arg->argv[arg->argn + 1],
194436285Sbrian                  addr + 1, &dummyaddr, &dummyint);
194536285Sbrian
194658044Sbrian      if (addr[0].s_addr == INADDR_ANY) {
194736285Sbrian        addr[0].s_addr = addr[1].s_addr;
194858044Sbrian        addr[1].s_addr = INADDR_ANY;
194958044Sbrian      }
195058044Sbrian      if (addr[0].s_addr == INADDR_NONE) {
195158044Sbrian        addr[0].s_addr = addr[1].s_addr;
195258044Sbrian        addr[1].s_addr = INADDR_NONE;
195358044Sbrian      }
195436285Sbrian    }
195536285Sbrian    break;
195638174Sbrian
195738174Sbrian  case VAR_CALLBACK:
195838174Sbrian    cx->cfg.callback.opmask = 0;
195938174Sbrian    for (dummyint = arg->argn; dummyint < arg->argc; dummyint++) {
196038174Sbrian      if (!strcasecmp(arg->argv[dummyint], "auth"))
196138174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_AUTH);
196238174Sbrian      else if (!strcasecmp(arg->argv[dummyint], "cbcp"))
196338174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_CBCP);
196438174Sbrian      else if (!strcasecmp(arg->argv[dummyint], "e.164")) {
196538174Sbrian        if (dummyint == arg->argc - 1)
196638174Sbrian          log_Printf(LogWARN, "No E.164 arg (E.164 ignored) !\n");
196738174Sbrian        else {
196838174Sbrian          cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_E164);
196938174Sbrian          strncpy(cx->cfg.callback.msg, arg->argv[++dummyint],
197038174Sbrian                  sizeof cx->cfg.callback.msg - 1);
197138174Sbrian          cx->cfg.callback.msg[sizeof cx->cfg.callback.msg - 1] = '\0';
197238174Sbrian        }
197338174Sbrian      } else if (!strcasecmp(arg->argv[dummyint], "none"))
197438174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_NONE);
197579119Sbrian      else {
197679119Sbrian        res = -1;
197779119Sbrian        break;
197879119Sbrian      }
197938174Sbrian    }
198038174Sbrian    if (cx->cfg.callback.opmask == CALLBACK_BIT(CALLBACK_NONE))
198138174Sbrian      cx->cfg.callback.opmask = 0;
198238174Sbrian    break;
198338174Sbrian
198438174Sbrian  case VAR_CBCP:
198538174Sbrian    cx->cfg.cbcp.delay = 0;
198638174Sbrian    *cx->cfg.cbcp.phone = '\0';
198738174Sbrian    cx->cfg.cbcp.fsmretry = DEF_FSMRETRY;
198838174Sbrian    if (arg->argc > arg->argn) {
198938174Sbrian      strncpy(cx->cfg.cbcp.phone, arg->argv[arg->argn],
199038174Sbrian              sizeof cx->cfg.cbcp.phone - 1);
199138174Sbrian      cx->cfg.cbcp.phone[sizeof cx->cfg.cbcp.phone - 1] = '\0';
199238174Sbrian      if (arg->argc > arg->argn + 1) {
199338174Sbrian        cx->cfg.cbcp.delay = atoi(arg->argv[arg->argn + 1]);
199438174Sbrian        if (arg->argc > arg->argn + 2) {
199538174Sbrian          long_val = atol(arg->argv[arg->argn + 2]);
199638174Sbrian          if (long_val < MIN_FSMRETRY)
199738174Sbrian            log_Printf(LogWARN, "%ld: Invalid CBCP FSM retry period - min %d\n",
199838174Sbrian                       long_val, MIN_FSMRETRY);
199938174Sbrian          else
200038174Sbrian            cx->cfg.cbcp.fsmretry = long_val;
200138174Sbrian        }
200238174Sbrian      }
200338174Sbrian    }
200438174Sbrian    break;
200538544Sbrian
200638544Sbrian  case VAR_CHOKED:
200738544Sbrian    arg->bundle->cfg.choked.timeout = atoi(argp);
200838544Sbrian    if (arg->bundle->cfg.choked.timeout <= 0)
200938544Sbrian      arg->bundle->cfg.choked.timeout = CHOKED_TIMEOUT;
201038544Sbrian    break;
201140665Sbrian
201240665Sbrian  case VAR_SENDPIPE:
201340665Sbrian    long_val = atol(argp);
201440665Sbrian    arg->bundle->ncp.ipcp.cfg.sendpipe = long_val;
201540665Sbrian    break;
201640665Sbrian
201740665Sbrian  case VAR_RECVPIPE:
201840665Sbrian    long_val = atol(argp);
201940665Sbrian    arg->bundle->ncp.ipcp.cfg.recvpipe = long_val;
202040665Sbrian    break;
202143313Sbrian
202243313Sbrian#ifndef NORADIUS
202343313Sbrian  case VAR_RADIUS:
202443313Sbrian    if (!*argp)
202543313Sbrian      *arg->bundle->radius.cfg.file = '\0';
202643313Sbrian    else if (access(argp, R_OK)) {
202743313Sbrian      log_Printf(LogWARN, "%s: %s\n", argp, strerror(errno));
202879119Sbrian      res = 1;
202979119Sbrian      break;
203043313Sbrian    } else {
203143313Sbrian      strncpy(arg->bundle->radius.cfg.file, argp,
203243313Sbrian              sizeof arg->bundle->radius.cfg.file - 1);
203343313Sbrian      arg->bundle->radius.cfg.file
203443313Sbrian        [sizeof arg->bundle->radius.cfg.file - 1] = '\0';
203543313Sbrian    }
203643313Sbrian    break;
203743313Sbrian#endif
203844073Sbrian
203944073Sbrian  case VAR_CD:
204044073Sbrian    if (*argp) {
204151699Sbrian      if (strcasecmp(argp, "off")) {
204251699Sbrian        long_val = atol(argp);
204351699Sbrian        if (long_val < 0)
204451699Sbrian          long_val = 0;
204551699Sbrian        cx->physical->cfg.cd.delay = long_val;
204651699Sbrian        cx->physical->cfg.cd.necessity = argp[strlen(argp)-1] == '!' ?
204751699Sbrian          CD_REQUIRED : CD_VARIABLE;
204851699Sbrian      } else
204951699Sbrian        cx->physical->cfg.cd.necessity = CD_NOTREQUIRED;
205044073Sbrian    } else {
205153733Sbrian      cx->physical->cfg.cd.delay = 0;
205253733Sbrian      cx->physical->cfg.cd.necessity = CD_DEFAULT;
205344073Sbrian    }
205444073Sbrian    break;
205536285Sbrian
205646686Sbrian  case VAR_PARITY:
205746686Sbrian    if (arg->argc == arg->argn + 1)
205879119Sbrian      res = physical_SetParity(arg->cx->physical, argp);
205946686Sbrian    else {
206079119Sbrian      log_Printf(LogWARN, "Parity value must be odd, even or none\n");
206179119Sbrian      res = 1;
206246686Sbrian    }
206346686Sbrian    break;
20646059Samurai
206546686Sbrian  case VAR_CRTSCTS:
206646686Sbrian    if (strcasecmp(argp, "on") == 0)
206736285Sbrian      physical_SetRtsCts(arg->cx->physical, 1);
206846686Sbrian    else if (strcasecmp(argp, "off") == 0)
206936285Sbrian      physical_SetRtsCts(arg->cx->physical, 0);
207046686Sbrian    else {
207179119Sbrian      log_Printf(LogWARN, "RTS/CTS value must be on or off\n");
207279119Sbrian      res = 1;
207346686Sbrian    }
207446686Sbrian    break;
207550867Sbrian
207650867Sbrian  case VAR_URGENTPORTS:
207751048Sbrian    if (arg->argn == arg->argc) {
207861430Sbrian      ipcp_SetUrgentTOS(&arg->bundle->ncp.ipcp);
207951048Sbrian      ipcp_ClearUrgentTcpPorts(&arg->bundle->ncp.ipcp);
208051048Sbrian      ipcp_ClearUrgentUdpPorts(&arg->bundle->ncp.ipcp);
208151048Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "udp")) {
208261430Sbrian      ipcp_SetUrgentTOS(&arg->bundle->ncp.ipcp);
208351048Sbrian      if (arg->argn == arg->argc - 1)
208451048Sbrian        ipcp_ClearUrgentUdpPorts(&arg->bundle->ncp.ipcp);
208551048Sbrian      else for (f = arg->argn + 1; f < arg->argc; f++)
208651048Sbrian        if (*arg->argv[f] == '+')
208751048Sbrian          ipcp_AddUrgentUdpPort(&arg->bundle->ncp.ipcp, atoi(arg->argv[f] + 1));
208851048Sbrian        else if (*arg->argv[f] == '-')
208951048Sbrian          ipcp_RemoveUrgentUdpPort(&arg->bundle->ncp.ipcp,
209051048Sbrian                                   atoi(arg->argv[f] + 1));
209151048Sbrian        else {
209251048Sbrian          if (f == arg->argn)
209351048Sbrian            ipcp_ClearUrgentUdpPorts(&arg->bundle->ncp.ipcp);
209451048Sbrian          ipcp_AddUrgentUdpPort(&arg->bundle->ncp.ipcp, atoi(arg->argv[f]));
209551048Sbrian        }
209661430Sbrian    } else if (arg->argn == arg->argc - 1 &&
209761430Sbrian               !strcasecmp(arg->argv[arg->argn], "none")) {
209861430Sbrian      ipcp_ClearUrgentTcpPorts(&arg->bundle->ncp.ipcp);
209961430Sbrian      ipcp_ClearUrgentUdpPorts(&arg->bundle->ncp.ipcp);
210061430Sbrian      ipcp_ClearUrgentTOS(&arg->bundle->ncp.ipcp);
210151048Sbrian    } else {
210261430Sbrian      ipcp_SetUrgentTOS(&arg->bundle->ncp.ipcp);
210351048Sbrian      first = arg->argn;
210451048Sbrian      if (!strcasecmp(arg->argv[first], "tcp") && ++first == arg->argc)
210551048Sbrian        ipcp_ClearUrgentTcpPorts(&arg->bundle->ncp.ipcp);
210651048Sbrian
210751048Sbrian      for (f = first; f < arg->argc; f++)
210851048Sbrian        if (*arg->argv[f] == '+')
210951048Sbrian          ipcp_AddUrgentTcpPort(&arg->bundle->ncp.ipcp, atoi(arg->argv[f] + 1));
211051048Sbrian        else if (*arg->argv[f] == '-')
211151048Sbrian          ipcp_RemoveUrgentTcpPort(&arg->bundle->ncp.ipcp,
211251048Sbrian                                   atoi(arg->argv[f] + 1));
211351048Sbrian        else {
211451048Sbrian          if (f == first)
211551048Sbrian            ipcp_ClearUrgentTcpPorts(&arg->bundle->ncp.ipcp);
211651048Sbrian          ipcp_AddUrgentTcpPort(&arg->bundle->ncp.ipcp, atoi(arg->argv[f]));
211751048Sbrian        }
211851048Sbrian    }
211950867Sbrian    break;
212020812Sjkh  }
212146686Sbrian
212279119Sbrian  return res;
212320812Sjkh}
212420812Sjkh
212530715Sbrianstatic struct cmdtab const SetCommands[] = {
212636285Sbrian  {"accmap", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
212736285Sbrian  "accmap value", "set accmap hex-value", (const void *)VAR_ACCMAP},
212828679Sbrian  {"authkey", "key", SetVariable, LOCAL_AUTH,
212936285Sbrian  "authentication key", "set authkey|key key", (const void *)VAR_AUTHKEY},
213028679Sbrian  {"authname", NULL, SetVariable, LOCAL_AUTH,
213136285Sbrian  "authentication name", "set authname name", (const void *)VAR_AUTHNAME},
213236285Sbrian  {"autoload", NULL, SetVariable, LOCAL_AUTH,
213336285Sbrian  "auto link [de]activation", "set autoload maxtime maxload mintime minload",
213436285Sbrian  (const void *)VAR_AUTOLOAD},
213550867Sbrian  {"bandwidth", NULL, mp_SetDatalinkBandwidth, LOCAL_AUTH | LOCAL_CX,
213650867Sbrian  "datalink bandwidth", "set bandwidth value"},
213738174Sbrian  {"callback", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
213838174Sbrian  "callback control", "set callback [none|auth|cbcp|"
213938174Sbrian  "E.164 *|number[,number]...]...", (const void *)VAR_CALLBACK},
214038174Sbrian  {"cbcp", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
214138174Sbrian  "CBCP control", "set cbcp [*|phone[,phone...] [delay [timeout]]]",
214238174Sbrian  (const void *)VAR_CBCP},
214344305Sbrian  {"ccpretry", "ccpretries", SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
214444305Sbrian   "CCP retries", "set ccpretry value [attempts]", (const void *)VAR_CCPRETRY},
214544073Sbrian  {"cd", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "Carrier delay requirement",
214644073Sbrian   "set cd value[!]", (const void *)VAR_CD},
214744305Sbrian  {"chapretry", "chapretries", SetVariable, LOCAL_AUTH | LOCAL_CX,
214844305Sbrian   "CHAP retries", "set chapretry value [attempts]",
214944305Sbrian   (const void *)VAR_CHAPRETRY},
215038544Sbrian  {"choked", NULL, SetVariable, LOCAL_AUTH,
215138544Sbrian  "choked timeout", "set choked [secs]", (const void *)VAR_CHOKED},
215246686Sbrian  {"ctsrts", "crtscts", SetVariable, LOCAL_AUTH | LOCAL_CX,
215346686Sbrian   "Use hardware flow control", "set ctsrts [on|off]",
215446686Sbrian   (const char *)VAR_CRTSCTS},
215536285Sbrian  {"deflate", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
215636285Sbrian  "deflate window sizes", "set deflate out-winsize in-winsize",
215736285Sbrian  (const void *) VAR_WINSIZE},
215867910Sbrian#ifdef HAVE_DES
215967910Sbrian  {"mppe", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
216079370Sbrian  "MPPE key size and state", "set mppe [40|56|128|* [stateful|stateless|*]]",
216178411Sbrian  (const void *) VAR_MPPE},
216267910Sbrian#endif
216336285Sbrian  {"device", "line", SetVariable, LOCAL_AUTH | LOCAL_CX,
216446686Sbrian  "physical device name", "set device|line device-name[,device-name]",
216536285Sbrian  (const void *) VAR_DEVICE},
216636285Sbrian  {"dial", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
216736285Sbrian  "dialing script", "set dial chat-script", (const void *) VAR_DIAL},
216836285Sbrian  {"dns", NULL, SetVariable, LOCAL_AUTH, "Domain Name Server",
216936285Sbrian  "set dns pri-addr [sec-addr]", (const void *)VAR_DNS},
217036285Sbrian  {"enddisc", NULL, mp_SetEnddisc, LOCAL_AUTH,
217136285Sbrian  "Endpoint Discriminator", "set enddisc [IP|magic|label|psn value]"},
217236285Sbrian  {"escape", NULL, SetEscape, LOCAL_AUTH | LOCAL_CX,
217336285Sbrian  "escape characters", "set escape hex-digit ..."},
217436285Sbrian  {"filter", NULL, filter_Set, LOCAL_AUTH,
217536285Sbrian  "packet filters", "set filter alive|dial|in|out rule-no permit|deny "
217649388Sbrian  "[src_addr[/width]] [dst_addr[/width]] [tcp|udp|icmp|ospf|igmp "
217748142Sbrian  "[src [lt|eq|gt port]] [dst [lt|eq|gt port]] [estab] [syn] [finrst]]"},
217836285Sbrian  {"hangup", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
217936285Sbrian  "hangup script", "set hangup chat-script", (const void *) VAR_HANGUP},
218036285Sbrian  {"ifaddr", NULL, SetInterfaceAddr, LOCAL_AUTH, "destination address",
218131343Sbrian  "set ifaddr [src-addr [dst-addr [netmask [trg-addr]]]]"},
218261534Sbrian  {"ifqueue", NULL, SetVariable, LOCAL_AUTH, "interface queue",
218361534Sbrian  "set ifqueue packets", (const void *)VAR_IFQUEUE},
218444305Sbrian  {"ipcpretry", "ipcpretries", SetVariable, LOCAL_AUTH, "IPCP retries",
218544305Sbrian   "set ipcpretry value [attempts]", (const void *)VAR_IPCPRETRY},
218644305Sbrian  {"lcpretry", "lcpretries", SetVariable, LOCAL_AUTH | LOCAL_CX, "LCP retries",
218744305Sbrian   "set lcpretry value [attempts]", (const void *)VAR_LCPRETRY},
218836712Sbrian  {"log", NULL, log_SetLevel, LOCAL_AUTH, "log level",
218967916Sbrian  "set log [local] [+|-]all|async|cbcp|ccp|chat|command|connect|debug|dns|hdlc|"
219058033Sbrian  "id0|ipcp|lcp|lqm|phase|physical|sync|tcp/ip|timer|tun..."},
219136285Sbrian  {"login", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
219236285Sbrian  "login script", "set login chat-script", (const void *) VAR_LOGIN},
219352488Sbrian  {"logout", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
219452488Sbrian  "logout script", "set logout chat-script", (const void *) VAR_LOGOUT},
219536285Sbrian  {"lqrperiod", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
219636285Sbrian  "LQR period", "set lqrperiod value", (const void *)VAR_LQRPERIOD},
219736285Sbrian  {"mode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "mode value",
219836285Sbrian  "set mode interactive|auto|ddial|background", (const void *)VAR_MODE},
219936285Sbrian  {"mrru", NULL, SetVariable, LOCAL_AUTH, "MRRU value",
220036285Sbrian  "set mrru value", (const void *)VAR_MRRU},
220136285Sbrian  {"mru", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
220278410Sbrian  "MRU value", "set mru [max[imum]] [value]", (const void *)VAR_MRU},
220378410Sbrian  {"mtu", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
220478410Sbrian  "interface MTU value", "set mtu [max[imum]] [value]", (const void *)VAR_MTU},
220536285Sbrian  {"nbns", NULL, SetVariable, LOCAL_AUTH, "NetBIOS Name Server",
220636285Sbrian  "set nbns pri-addr [sec-addr]", (const void *)VAR_NBNS},
220736285Sbrian  {"openmode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "open mode",
220836285Sbrian  "set openmode active|passive [secs]", (const void *)VAR_OPENMODE},
220944305Sbrian  {"papretry", "papretries", SetVariable, LOCAL_AUTH | LOCAL_CX, "PAP retries",
221044305Sbrian   "set papretry value [attempts]", (const void *)VAR_PAPRETRY},
221146686Sbrian  {"parity", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "serial parity",
221246686Sbrian   "set parity [odd|even|none]", (const void *)VAR_PARITY},
221336285Sbrian  {"phone", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "telephone number(s)",
221436285Sbrian  "set phone phone1[:phone2[...]]", (const void *)VAR_PHONE},
221540679Sbrian  {"proctitle", "title", SetProcTitle, LOCAL_AUTH,
221640679Sbrian  "Process title", "set proctitle [value]"},
221743313Sbrian#ifndef NORADIUS
221843313Sbrian  {"radius", NULL, SetVariable, LOCAL_AUTH,
221943313Sbrian  "RADIUS Config", "set radius cfgfile", (const void *)VAR_RADIUS},
222043313Sbrian#endif
222136285Sbrian  {"reconnect", NULL, datalink_SetReconnect, LOCAL_AUTH | LOCAL_CX,
222236285Sbrian  "Reconnect timeout", "set reconnect value ntries"},
222340665Sbrian  {"recvpipe", NULL, SetVariable, LOCAL_AUTH,
222440665Sbrian  "RECVPIPE value", "set recvpipe value", (const void *)VAR_RECVPIPE},
222536285Sbrian  {"redial", NULL, datalink_SetRedial, LOCAL_AUTH | LOCAL_CX,
222644468Sbrian  "Redial timeout", "set redial secs[+inc[-incmax]][.next] [attempts]"},
222740665Sbrian  {"sendpipe", NULL, SetVariable, LOCAL_AUTH,
222840665Sbrian  "SENDPIPE value", "set sendpipe value", (const void *)VAR_SENDPIPE},
222971657Sbrian  {"server", "socket", SetServer, LOCAL_AUTH, "diagnostic port",
223071657Sbrian  "set server|socket TcpPort|LocalName|none|open|closed [password [mask]]"},
223136285Sbrian  {"speed", NULL, SetModemSpeed, LOCAL_AUTH | LOCAL_CX,
223246686Sbrian  "physical speed", "set speed value|sync"},
223336285Sbrian  {"stopped", NULL, SetStoppedTimeout, LOCAL_AUTH | LOCAL_CX,
223436285Sbrian  "STOPPED timeouts", "set stopped [LCPseconds [CCPseconds]]"},
223536285Sbrian  {"timeout", NULL, SetVariable, LOCAL_AUTH, "Idle timeout",
223636285Sbrian  "set timeout idletime", (const void *)VAR_IDLETIMEOUT},
223751048Sbrian  {"urgent", NULL, SetVariable, LOCAL_AUTH, "urgent ports",
223851048Sbrian  "set urgent [tcp|udp] [+|-]port...", (const void *)VAR_URGENTPORTS},
223936285Sbrian  {"vj", NULL, ipcp_vjset, LOCAL_AUTH,
224036285Sbrian  "vj values", "set vj slots|slotcomp [value]"},
224128679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
224231343Sbrian  "Display this message", "set help|? [command]", SetCommands},
224328679Sbrian  {NULL, NULL, NULL},
22446059Samurai};
22456059Samurai
22466059Samuraistatic int
224731343SbrianSetCommand(struct cmdargs const *arg)
22486059Samurai{
224936285Sbrian  if (arg->argc > arg->argn)
225036285Sbrian    FindExec(arg->bundle, SetCommands, arg->argc, arg->argn, arg->argv,
225136285Sbrian             arg->prompt, arg->cx);
225236285Sbrian  else if (arg->prompt)
225336285Sbrian    prompt_Printf(arg->prompt, "Use `set ?' to get a list or `set ? <var>' for"
225458044Sbrian	          " syntax help.\n");
22556059Samurai  else
225636285Sbrian    log_Printf(LogWARN, "set command must have arguments\n");
225726516Sbrian
225826516Sbrian  return 0;
22596059Samurai}
22606059Samurai
22616059Samuraistatic int
226231343SbrianAddCommand(struct cmdargs const *arg)
22636059Samurai{
22646059Samurai  struct in_addr dest, gateway, netmask;
226536285Sbrian  int gw, addrs;
22666059Samurai
226736285Sbrian  if (arg->argc != arg->argn+3 && arg->argc != arg->argn+2)
226831598Sbrian    return -1;
226931598Sbrian
227036285Sbrian  addrs = 0;
227136285Sbrian  if (arg->argc == arg->argn+2) {
227236285Sbrian    if (!strcasecmp(arg->argv[arg->argn], "default"))
227336285Sbrian      dest.s_addr = netmask.s_addr = INADDR_ANY;
227431598Sbrian    else {
227536285Sbrian      int width;
227636285Sbrian
227743313Sbrian      if (!ParseAddr(&arg->bundle->ncp.ipcp, arg->argv[arg->argn],
227836285Sbrian	             &dest, &netmask, &width))
227936285Sbrian        return -1;
228036285Sbrian      if (!strncasecmp(arg->argv[arg->argn], "MYADDR", 6))
228136285Sbrian        addrs = ROUTE_DSTMYADDR;
228236285Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "HISADDR", 7))
228336285Sbrian        addrs = ROUTE_DSTHISADDR;
228458044Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "DNS0", 4))
228558044Sbrian        addrs = ROUTE_DSTDNS0;
228658044Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "DNS1", 4))
228758044Sbrian        addrs = ROUTE_DSTDNS1;
228831598Sbrian    }
228936285Sbrian    gw = 1;
229034536Sbrian  } else {
229136285Sbrian    if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
229236285Sbrian      addrs = ROUTE_DSTMYADDR;
229336285Sbrian      dest = arg->bundle->ncp.ipcp.my_ip;
229436285Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
229536285Sbrian      addrs = ROUTE_DSTHISADDR;
229636285Sbrian      dest = arg->bundle->ncp.ipcp.peer_ip;
229758044Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "DNS0") == 0) {
229858044Sbrian      addrs = ROUTE_DSTDNS0;
229958044Sbrian      dest = arg->bundle->ncp.ipcp.ns.dns[0];
230058044Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "DNS1") == 0) {
230158044Sbrian      addrs = ROUTE_DSTDNS1;
230258044Sbrian      dest = arg->bundle->ncp.ipcp.ns.dns[1];
230365263Sbrian    } else {
230436285Sbrian      dest = GetIpAddr(arg->argv[arg->argn]);
230565263Sbrian      if (dest.s_addr == INADDR_NONE) {
230665263Sbrian        log_Printf(LogWARN, "%s: Invalid destination address\n",
230765263Sbrian                   arg->argv[arg->argn]);
230865263Sbrian        return -1;
230965263Sbrian      }
231065263Sbrian    }
231136285Sbrian    netmask = GetIpAddr(arg->argv[arg->argn+1]);
231231598Sbrian    gw = 2;
23136059Samurai  }
231436285Sbrian
231536285Sbrian  if (strcasecmp(arg->argv[arg->argn+gw], "HISADDR") == 0) {
231636285Sbrian    gateway = arg->bundle->ncp.ipcp.peer_ip;
231736285Sbrian    addrs |= ROUTE_GWHISADDR;
231865263Sbrian  } else {
231936285Sbrian    gateway = GetIpAddr(arg->argv[arg->argn+gw]);
232065263Sbrian    if (gateway.s_addr == INADDR_NONE) {
232165263Sbrian      log_Printf(LogWARN, "%s: Invalid gateway address\n",
232265263Sbrian                 arg->argv[arg->argn + gw]);
232365263Sbrian      return -1;
232465263Sbrian    }
232565263Sbrian  }
232636285Sbrian
232775212Sbrian  if (rt_Set(arg->bundle, RTM_ADD, dest, gateway, netmask,
232843313Sbrian                  arg->cmd->args ? 1 : 0, (addrs & ROUTE_GWHISADDR) ? 1 : 0)
232943313Sbrian      && addrs != ROUTE_STATIC)
233036285Sbrian    route_Add(&arg->bundle->ncp.ipcp.route, addrs, dest, netmask, gateway);
233136285Sbrian
233231598Sbrian  return 0;
23336059Samurai}
23346059Samurai
23356059Samuraistatic int
233631343SbrianDeleteCommand(struct cmdargs const *arg)
23376059Samurai{
233831598Sbrian  struct in_addr dest, none;
233936285Sbrian  int addrs;
23406059Samurai
234136285Sbrian  if (arg->argc == arg->argn+1) {
234236285Sbrian    if(strcasecmp(arg->argv[arg->argn], "all") == 0) {
234336285Sbrian      route_IfDelete(arg->bundle, 0);
234436285Sbrian      route_DeleteAll(&arg->bundle->ncp.ipcp.route);
234536285Sbrian    } else {
234636285Sbrian      addrs = 0;
234736285Sbrian      if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
234836285Sbrian        dest = arg->bundle->ncp.ipcp.my_ip;
234936285Sbrian        addrs = ROUTE_DSTMYADDR;
235036285Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
235136285Sbrian        dest = arg->bundle->ncp.ipcp.peer_ip;
235236285Sbrian        addrs = ROUTE_DSTHISADDR;
235358044Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "DNS0") == 0) {
235458044Sbrian        dest = arg->bundle->ncp.ipcp.ns.dns[0];
235558044Sbrian        addrs = ROUTE_DSTDNS0;
235658044Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "DNS1") == 0) {
235758044Sbrian        dest = arg->bundle->ncp.ipcp.ns.dns[1];
235858044Sbrian        addrs = ROUTE_DSTDNS1;
235936285Sbrian      } else {
236044279Sbrian        dest = GetIpAddr(arg->argv[arg->argn]);
236144279Sbrian        if (dest.s_addr == INADDR_NONE) {
236244279Sbrian          log_Printf(LogWARN, "%s: Invalid IP address\n", arg->argv[arg->argn]);
236344279Sbrian          return -1;
236444279Sbrian        }
236536285Sbrian        addrs = ROUTE_STATIC;
236636285Sbrian      }
236731598Sbrian      none.s_addr = INADDR_ANY;
236875212Sbrian      rt_Set(arg->bundle, RTM_DELETE, dest, none, none,
236937927Sbrian                      arg->cmd->args ? 1 : 0, 0);
237036285Sbrian      route_Delete(&arg->bundle->ncp.ipcp.route, addrs, dest);
237131598Sbrian    }
237234536Sbrian  } else
237326516Sbrian    return -1;
237426516Sbrian
237526516Sbrian  return 0;
23766059Samurai}
23776059Samurai
237850059Sbrian#ifndef NONAT
237926031Sbrianstatic int
238058867SbrianNatEnable(struct cmdargs const *arg)
238126031Sbrian{
238236285Sbrian  if (arg->argc == arg->argn+1) {
238336285Sbrian    if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
238450059Sbrian      if (!arg->bundle->NatEnabled) {
238546686Sbrian        if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED)
238646686Sbrian          PacketAliasSetAddress(arg->bundle->ncp.ipcp.my_ip);
238750059Sbrian        arg->bundle->NatEnabled = 1;
238846686Sbrian      }
238937191Sbrian      return 0;
239036285Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "no") == 0) {
239150059Sbrian      arg->bundle->NatEnabled = 0;
239240561Sbrian      arg->bundle->cfg.opt &= ~OPT_IFACEALIAS;
239340561Sbrian      /* Don't iface_Clear() - there may be manually configured addresses */
239426516Sbrian      return 0;
239526142Sbrian    }
239635449Sbrian  }
239736285Sbrian
239826516Sbrian  return -1;
239926031Sbrian}
240026031Sbrian
240126031Sbrian
240226031Sbrianstatic int
240358867SbrianNatOption(struct cmdargs const *arg)
240426031Sbrian{
240538559Sbrian  long param = (long)arg->cmd->args;
240638559Sbrian
240736285Sbrian  if (arg->argc == arg->argn+1) {
240836285Sbrian    if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
240950059Sbrian      if (arg->bundle->NatEnabled) {
241037191Sbrian	PacketAliasSetMode(param, param);
241128679Sbrian	return 0;
241228679Sbrian      }
241350059Sbrian      log_Printf(LogWARN, "nat not enabled\n");
241436285Sbrian    } else if (strcmp(arg->argv[arg->argn], "no") == 0) {
241550059Sbrian      if (arg->bundle->NatEnabled) {
241637191Sbrian	PacketAliasSetMode(0, param);
241728679Sbrian	return 0;
241828679Sbrian      }
241950059Sbrian      log_Printf(LogWARN, "nat not enabled\n");
242028679Sbrian    }
242135449Sbrian  }
242228679Sbrian  return -1;
242326031Sbrian}
242450059Sbrian#endif /* #ifndef NONAT */
242531121Sbrian
242631121Sbrianstatic int
242736285SbrianLinkCommand(struct cmdargs const *arg)
242836285Sbrian{
242936285Sbrian  if (arg->argc > arg->argn+1) {
243036285Sbrian    char namelist[LINE_LEN];
243136285Sbrian    struct datalink *cx;
243236285Sbrian    char *name;
243336285Sbrian    int result = 0;
243436285Sbrian
243536285Sbrian    if (!strcmp(arg->argv[arg->argn], "*")) {
243636285Sbrian      struct datalink *dl;
243736285Sbrian
243836285Sbrian      cx = arg->bundle->links;
243936285Sbrian      while (cx) {
244036285Sbrian        /* Watch it, the command could be a ``remove'' */
244136285Sbrian        dl = cx->next;
244236285Sbrian        FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
244336285Sbrian                 arg->prompt, cx);
244436285Sbrian        for (cx = arg->bundle->links; cx; cx = cx->next)
244536285Sbrian          if (cx == dl)
244636285Sbrian            break;		/* Pointer's still valid ! */
244736285Sbrian      }
244836285Sbrian    } else {
244936285Sbrian      strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
245036285Sbrian      namelist[sizeof namelist - 1] = '\0';
245136285Sbrian      for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
245236285Sbrian        if (!bundle2datalink(arg->bundle, name)) {
245336285Sbrian          log_Printf(LogWARN, "link: %s: Invalid link name\n", name);
245436285Sbrian          return 1;
245536285Sbrian        }
245636285Sbrian
245736285Sbrian      strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
245836285Sbrian      namelist[sizeof namelist - 1] = '\0';
245936285Sbrian      for(name = strtok(namelist, ", "); name; name = strtok(NULL,", ")) {
246036285Sbrian        cx = bundle2datalink(arg->bundle, name);
246136285Sbrian        if (cx)
246236285Sbrian          FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
246336285Sbrian                   arg->prompt, cx);
246436285Sbrian        else {
246536285Sbrian          log_Printf(LogWARN, "link: %s: Invalidated link name !\n", name);
246636285Sbrian          result++;
246736285Sbrian        }
246836285Sbrian      }
246936285Sbrian    }
247036285Sbrian    return result;
247136285Sbrian  }
247236285Sbrian
247336285Sbrian  log_Printf(LogWARN, "Usage: %s\n", arg->cmd->syntax);
247436285Sbrian  return 2;
247536285Sbrian}
247636285Sbrian
247736285Sbrianstruct link *
247836285Sbriancommand_ChooseLink(struct cmdargs const *arg)
247936285Sbrian{
248036285Sbrian  if (arg->cx)
248136285Sbrian    return &arg->cx->physical->link;
248237210Sbrian  else if (!arg->bundle->ncp.mp.cfg.mrru) {
248336285Sbrian    struct datalink *dl = bundle2datalink(arg->bundle, NULL);
248437210Sbrian    if (dl)
248537210Sbrian      return &dl->physical->link;
248636285Sbrian  }
248737210Sbrian  return &arg->bundle->ncp.mp.link;
248836285Sbrian}
248936285Sbrian
249036285Sbrianstatic const char *
249136285Sbrianident_cmd(const char *cmd, unsigned *keep, unsigned *add)
249236285Sbrian{
249336285Sbrian  const char *result;
249436285Sbrian
249536285Sbrian  switch (*cmd) {
249636285Sbrian    case 'A':
249736285Sbrian    case 'a':
249836285Sbrian      result = "accept";
249936285Sbrian      *keep = NEG_MYMASK;
250036285Sbrian      *add = NEG_ACCEPTED;
250136285Sbrian      break;
250236285Sbrian    case 'D':
250336285Sbrian    case 'd':
250436285Sbrian      switch (cmd[1]) {
250536285Sbrian        case 'E':
250636285Sbrian        case 'e':
250736285Sbrian          result = "deny";
250836285Sbrian          *keep = NEG_MYMASK;
250936285Sbrian          *add = 0;
251036285Sbrian          break;
251136285Sbrian        case 'I':
251236285Sbrian        case 'i':
251336285Sbrian          result = "disable";
251436285Sbrian          *keep = NEG_HISMASK;
251536285Sbrian          *add = 0;
251636285Sbrian          break;
251736285Sbrian        default:
251836285Sbrian          return NULL;
251936285Sbrian      }
252036285Sbrian      break;
252136285Sbrian    case 'E':
252236285Sbrian    case 'e':
252336285Sbrian      result = "enable";
252436285Sbrian      *keep = NEG_HISMASK;
252536285Sbrian      *add = NEG_ENABLED;
252636285Sbrian      break;
252736285Sbrian    default:
252836285Sbrian      return NULL;
252936285Sbrian  }
253036285Sbrian
253136285Sbrian  return result;
253236285Sbrian}
253336285Sbrian
253436285Sbrianstatic int
253536285SbrianOptSet(struct cmdargs const *arg)
253636285Sbrian{
253737574Sbrian  int bit = (int)(long)arg->cmd->args;
253836285Sbrian  const char *cmd;
253936285Sbrian  unsigned keep;			/* Keep these bits */
254036285Sbrian  unsigned add;				/* Add these bits */
254136285Sbrian
254236285Sbrian  if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL)
254336285Sbrian    return 1;
254436285Sbrian
254536285Sbrian  if (add)
254636285Sbrian    arg->bundle->cfg.opt |= bit;
254736285Sbrian  else
254836285Sbrian    arg->bundle->cfg.opt &= ~bit;
254936285Sbrian  return 0;
255036285Sbrian}
255136285Sbrian
255236285Sbrianstatic int
255340561SbrianIfaceAliasOptSet(struct cmdargs const *arg)
255440561Sbrian{
255540561Sbrian  unsigned save = arg->bundle->cfg.opt;
255640561Sbrian  int result = OptSet(arg);
255740561Sbrian
255840561Sbrian  if (result == 0)
255950059Sbrian    if (Enabled(arg->bundle, OPT_IFACEALIAS) && !arg->bundle->NatEnabled) {
256040561Sbrian      arg->bundle->cfg.opt = save;
256150059Sbrian      log_Printf(LogWARN, "Cannot enable iface-alias without NAT\n");
256240561Sbrian      result = 2;
256340561Sbrian    }
256440561Sbrian
256540561Sbrian  return result;
256640561Sbrian}
256740561Sbrian
256840561Sbrianstatic int
256936285SbrianNegotiateSet(struct cmdargs const *arg)
257036285Sbrian{
257137210Sbrian  long param = (long)arg->cmd->args;
257236285Sbrian  struct link *l = command_ChooseLink(arg);	/* LOCAL_CX_OPT uses this */
257336285Sbrian  struct datalink *cx = arg->cx;	/* LOCAL_CX uses this */
257436285Sbrian  const char *cmd;
257536285Sbrian  unsigned keep;			/* Keep these bits */
257636285Sbrian  unsigned add;				/* Add these bits */
257736285Sbrian
257836285Sbrian  if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL)
257936285Sbrian    return 1;
258036285Sbrian
258136285Sbrian  if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
258236285Sbrian    log_Printf(LogWARN, "%s %s: No context (use the `link' command)\n",
258336285Sbrian              cmd, arg->cmd->name);
258436285Sbrian    return 2;
258536285Sbrian  } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
258636285Sbrian    log_Printf(LogWARN, "%s %s: Redundant context (%s) ignored\n",
258736285Sbrian              cmd, arg->cmd->name, cx->name);
258836285Sbrian    cx = NULL;
258936285Sbrian  }
259036285Sbrian
259136285Sbrian  switch (param) {
259236285Sbrian    case NEG_ACFCOMP:
259336285Sbrian      cx->physical->link.lcp.cfg.acfcomp &= keep;
259436285Sbrian      cx->physical->link.lcp.cfg.acfcomp |= add;
259536285Sbrian      break;
259644106Sbrian    case NEG_CHAP05:
259744106Sbrian      cx->physical->link.lcp.cfg.chap05 &= keep;
259844106Sbrian      cx->physical->link.lcp.cfg.chap05 |= add;
259936285Sbrian      break;
260044106Sbrian#ifdef HAVE_DES
260144106Sbrian    case NEG_CHAP80:
260244106Sbrian      cx->physical->link.lcp.cfg.chap80nt &= keep;
260344106Sbrian      cx->physical->link.lcp.cfg.chap80nt |= add;
260444106Sbrian      break;
260544106Sbrian    case NEG_CHAP80LM:
260644106Sbrian      cx->physical->link.lcp.cfg.chap80lm &= keep;
260744106Sbrian      cx->physical->link.lcp.cfg.chap80lm |= add;
260844106Sbrian      break;
260967910Sbrian    case NEG_CHAP81:
261067910Sbrian      cx->physical->link.lcp.cfg.chap81 &= keep;
261167910Sbrian      cx->physical->link.lcp.cfg.chap81 |= add;
261267910Sbrian      break;
261367910Sbrian    case NEG_MPPE:
261467910Sbrian      l->ccp.cfg.neg[CCP_NEG_MPPE] &= keep;
261567910Sbrian      l->ccp.cfg.neg[CCP_NEG_MPPE] |= add;
261667910Sbrian      break;
261744106Sbrian#endif
261836285Sbrian    case NEG_DEFLATE:
261936285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE] &= keep;
262036285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE] |= add;
262136285Sbrian      break;
262236285Sbrian    case NEG_DNS:
262336285Sbrian      arg->bundle->ncp.ipcp.cfg.ns.dns_neg &= keep;
262436285Sbrian      arg->bundle->ncp.ipcp.cfg.ns.dns_neg |= add;
262536285Sbrian      break;
262647858Sbrian    case NEG_ENDDISC:
262747858Sbrian      arg->bundle->ncp.mp.cfg.negenddisc &= keep;
262847858Sbrian      arg->bundle->ncp.mp.cfg.negenddisc |= add;
262947858Sbrian      break;
263036285Sbrian    case NEG_LQR:
263136285Sbrian      cx->physical->link.lcp.cfg.lqr &= keep;
263236285Sbrian      cx->physical->link.lcp.cfg.lqr |= add;
263336285Sbrian      break;
263436285Sbrian    case NEG_PAP:
263536285Sbrian      cx->physical->link.lcp.cfg.pap &= keep;
263636285Sbrian      cx->physical->link.lcp.cfg.pap |= add;
263736285Sbrian      break;
263836285Sbrian    case NEG_PPPDDEFLATE:
263936285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE24] &= keep;
264036285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE24] |= add;
264136285Sbrian      break;
264236285Sbrian    case NEG_PRED1:
264336285Sbrian      l->ccp.cfg.neg[CCP_NEG_PRED1] &= keep;
264436285Sbrian      l->ccp.cfg.neg[CCP_NEG_PRED1] |= add;
264536285Sbrian      break;
264636285Sbrian    case NEG_PROTOCOMP:
264736285Sbrian      cx->physical->link.lcp.cfg.protocomp &= keep;
264836285Sbrian      cx->physical->link.lcp.cfg.protocomp |= add;
264936285Sbrian      break;
265036285Sbrian    case NEG_SHORTSEQ:
265140622Sbrian      switch (bundle_Phase(arg->bundle)) {
265240622Sbrian        case PHASE_DEAD:
265340622Sbrian          break;
265440622Sbrian        case PHASE_ESTABLISH:
265540622Sbrian          /* Make sure none of our links are DATALINK_LCP or greater */
265640622Sbrian          if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) {
265740622Sbrian            log_Printf(LogWARN, "shortseq: Only changable before"
265840622Sbrian                       " LCP negotiations\n");
265940622Sbrian            return 1;
266040622Sbrian          }
266140622Sbrian          break;
266240622Sbrian        default:
266340622Sbrian          log_Printf(LogWARN, "shortseq: Only changable at phase"
266440622Sbrian                     " DEAD/ESTABLISH\n");
266540622Sbrian          return 1;
266636285Sbrian      }
266740622Sbrian      arg->bundle->ncp.mp.cfg.shortseq &= keep;
266840622Sbrian      arg->bundle->ncp.mp.cfg.shortseq |= add;
266936285Sbrian      break;
267036285Sbrian    case NEG_VJCOMP:
267136285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.neg &= keep;
267236285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.neg |= add;
267336285Sbrian      break;
267436285Sbrian  }
267536285Sbrian
267636285Sbrian  return 0;
267736285Sbrian}
267836285Sbrian
267936285Sbrianstatic struct cmdtab const NegotiateCommands[] = {
268062778Sbrian  {"filter-decapsulation", NULL, OptSet, LOCAL_AUTH,
268162778Sbrian  "filter on PPPoUDP payloads", "disable|enable",
268262778Sbrian  (const void *)OPT_FILTERDECAP},
268336285Sbrian  {"idcheck", NULL, OptSet, LOCAL_AUTH, "Check FSM reply ids",
268436285Sbrian  "disable|enable", (const void *)OPT_IDCHECK},
268540666Sbrian  {"iface-alias", NULL, IfaceAliasOptSet, LOCAL_AUTH,
268662778Sbrian  "retain interface addresses", "disable|enable",
268762778Sbrian  (const void *)OPT_IFACEALIAS},
268847689Sbrian  {"keep-session", NULL, OptSet, LOCAL_AUTH, "Retain device session leader",
268947689Sbrian  "disable|enable", (const void *)OPT_KEEPSESSION},
269036285Sbrian  {"loopback", NULL, OptSet, LOCAL_AUTH, "Loop packets for local iface",
269136285Sbrian  "disable|enable", (const void *)OPT_LOOPBACK},
269236285Sbrian  {"passwdauth", NULL, OptSet, LOCAL_AUTH, "Use passwd file",
269336285Sbrian  "disable|enable", (const void *)OPT_PASSWDAUTH},
269440665Sbrian  {"proxy", NULL, OptSet, LOCAL_AUTH, "Create a proxy ARP entry",
269536285Sbrian  "disable|enable", (const void *)OPT_PROXY},
269640665Sbrian  {"proxyall", NULL, OptSet, LOCAL_AUTH, "Proxy ARP for all remote hosts",
269740665Sbrian  "disable|enable", (const void *)OPT_PROXYALL},
269836285Sbrian  {"sroutes", NULL, OptSet, LOCAL_AUTH, "Use sticky routes",
269936285Sbrian  "disable|enable", (const void *)OPT_SROUTES},
270069303Sbrian  {"tcpmssfixup", "mssfixup", OptSet, LOCAL_AUTH, "Modify MSS options",
270169303Sbrian  "disable|enable", (const void *)OPT_TCPMSSFIXUP},
270236285Sbrian  {"throughput", NULL, OptSet, LOCAL_AUTH, "Rolling throughput",
270336285Sbrian  "disable|enable", (const void *)OPT_THROUGHPUT},
270436285Sbrian  {"utmp", NULL, OptSet, LOCAL_AUTH, "Log connections in utmp",
270536285Sbrian  "disable|enable", (const void *)OPT_UTMP},
270636285Sbrian
270769303Sbrian#define OPT_MAX 11	/* accept/deny allowed below and not above */
270836285Sbrian
270936285Sbrian  {"acfcomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
271036285Sbrian  "Address & Control field compression", "accept|deny|disable|enable",
271136285Sbrian  (const void *)NEG_ACFCOMP},
271244106Sbrian  {"chap", "chap05", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
271336285Sbrian  "Challenge Handshake Authentication Protocol", "accept|deny|disable|enable",
271444106Sbrian  (const void *)NEG_CHAP05},
271544106Sbrian#ifdef HAVE_DES
271644106Sbrian  {"mschap", "chap80nt", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
271744106Sbrian  "Microsoft (NT) CHAP", "accept|deny|disable|enable",
271844106Sbrian  (const void *)NEG_CHAP80},
271944106Sbrian  {"LANMan", "chap80lm", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
272044106Sbrian  "Microsoft (NT) CHAP", "accept|deny|disable|enable",
272144106Sbrian  (const void *)NEG_CHAP80LM},
272267910Sbrian  {"mschapv2", "chap81", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
272367910Sbrian  "Microsoft CHAP v2", "accept|deny|disable|enable",
272467910Sbrian  (const void *)NEG_CHAP81},
272567910Sbrian  {"mppe", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
272667910Sbrian  "MPPE encryption", "accept|deny|disable|enable",
272767910Sbrian  (const void *)NEG_MPPE},
272844106Sbrian#endif
272936285Sbrian  {"deflate", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
273036285Sbrian  "Deflate compression", "accept|deny|disable|enable",
273136285Sbrian  (const void *)NEG_DEFLATE},
273236285Sbrian  {"deflate24", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
273336285Sbrian  "Deflate (type 24) compression", "accept|deny|disable|enable",
273436285Sbrian  (const void *)NEG_PPPDDEFLATE},
273536285Sbrian  {"dns", NULL, NegotiateSet, LOCAL_AUTH,
273636285Sbrian  "DNS specification", "accept|deny|disable|enable", (const void *)NEG_DNS},
273747858Sbrian  {"enddisc", NULL, NegotiateSet, LOCAL_AUTH, "ENDDISC negotiation",
273847858Sbrian  "accept|deny|disable|enable", (const void *)NEG_ENDDISC},
273936285Sbrian  {"lqr", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
274036285Sbrian  "Link Quality Reports", "accept|deny|disable|enable",
274136285Sbrian  (const void *)NEG_LQR},
274236285Sbrian  {"pap", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
274336285Sbrian  "Password Authentication protocol", "accept|deny|disable|enable",
274436285Sbrian  (const void *)NEG_PAP},
274536285Sbrian  {"pred1", "predictor1", NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
274636285Sbrian  "Predictor 1 compression", "accept|deny|disable|enable",
274736285Sbrian  (const void *)NEG_PRED1},
274836285Sbrian  {"protocomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
274936285Sbrian  "Protocol field compression", "accept|deny|disable|enable",
275036285Sbrian  (const void *)NEG_PROTOCOMP},
275136285Sbrian  {"shortseq", NULL, NegotiateSet, LOCAL_AUTH,
275236285Sbrian  "MP Short Sequence Numbers", "accept|deny|disable|enable",
275336285Sbrian  (const void *)NEG_SHORTSEQ},
275436285Sbrian  {"vjcomp", NULL, NegotiateSet, LOCAL_AUTH,
275536285Sbrian  "Van Jacobson header compression", "accept|deny|disable|enable",
275636285Sbrian  (const void *)NEG_VJCOMP},
275736285Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
275836285Sbrian  "Display this message", "accept|deny|disable|enable help|? [value]",
275936285Sbrian  NegotiateCommands},
276036285Sbrian  {NULL, NULL, NULL},
276136285Sbrian};
276236285Sbrian
276336285Sbrianstatic int
276436285SbrianNegotiateCommand(struct cmdargs const *arg)
276536285Sbrian{
276636285Sbrian  if (arg->argc > arg->argn) {
276736285Sbrian    char const *argv[3];
276836285Sbrian    unsigned keep, add;
276936285Sbrian    int n;
277036285Sbrian
277136285Sbrian    if ((argv[0] = ident_cmd(arg->argv[arg->argn-1], &keep, &add)) == NULL)
277236285Sbrian      return -1;
277336285Sbrian    argv[2] = NULL;
277436285Sbrian
277536285Sbrian    for (n = arg->argn; n < arg->argc; n++) {
277636285Sbrian      argv[1] = arg->argv[n];
277736285Sbrian      FindExec(arg->bundle, NegotiateCommands + (keep == NEG_HISMASK ?
277836285Sbrian               0 : OPT_MAX), 2, 1, argv, arg->prompt, arg->cx);
277936285Sbrian    }
278036285Sbrian  } else if (arg->prompt)
278136285Sbrian    prompt_Printf(arg->prompt, "Use `%s ?' to get a list.\n",
278236285Sbrian	    arg->argv[arg->argn-1]);
278336285Sbrian  else
278436285Sbrian    log_Printf(LogWARN, "%s command must have arguments\n",
278536285Sbrian              arg->argv[arg->argn] );
278636285Sbrian
278736285Sbrian  return 0;
278836285Sbrian}
278936285Sbrian
279036285Sbrianconst char *
279136285Sbriancommand_ShowNegval(unsigned val)
279236285Sbrian{
279336285Sbrian  switch (val&3) {
279436285Sbrian    case 1: return "disabled & accepted";
279536285Sbrian    case 2: return "enabled & denied";
279636285Sbrian    case 3: return "enabled & accepted";
279736285Sbrian  }
279836285Sbrian  return "disabled & denied";
279936285Sbrian}
280036934Sbrian
280136934Sbrianstatic int
280236934SbrianClearCommand(struct cmdargs const *arg)
280336934Sbrian{
280436934Sbrian  struct pppThroughput *t;
280536934Sbrian  struct datalink *cx;
280636934Sbrian  int i, clear_type;
280736934Sbrian
280836934Sbrian  if (arg->argc < arg->argn + 1)
280936934Sbrian    return -1;
281036934Sbrian
281146686Sbrian  if (strcasecmp(arg->argv[arg->argn], "physical") == 0) {
281236934Sbrian    cx = arg->cx;
281336934Sbrian    if (!cx)
281436934Sbrian      cx = bundle2datalink(arg->bundle, NULL);
281536934Sbrian    if (!cx) {
281646686Sbrian      log_Printf(LogWARN, "A link must be specified for ``clear physical''\n");
281736934Sbrian      return 1;
281836934Sbrian    }
281964652Sbrian    t = &cx->physical->link.stats.total;
282036934Sbrian  } else if (strcasecmp(arg->argv[arg->argn], "ipcp") == 0)
282136934Sbrian    t = &arg->bundle->ncp.ipcp.throughput;
282236934Sbrian  else
282336934Sbrian    return -1;
282436934Sbrian
282536934Sbrian  if (arg->argc > arg->argn + 1) {
282636934Sbrian    clear_type = 0;
282736934Sbrian    for (i = arg->argn + 1; i < arg->argc; i++)
282836934Sbrian      if (strcasecmp(arg->argv[i], "overall") == 0)
282936934Sbrian        clear_type |= THROUGHPUT_OVERALL;
283036934Sbrian      else if (strcasecmp(arg->argv[i], "current") == 0)
283136934Sbrian        clear_type |= THROUGHPUT_CURRENT;
283236934Sbrian      else if (strcasecmp(arg->argv[i], "peak") == 0)
283336934Sbrian        clear_type |= THROUGHPUT_PEAK;
283436934Sbrian      else
283536934Sbrian        return -1;
283636934Sbrian  } else
283736934Sbrian    clear_type = THROUGHPUT_ALL;
283836934Sbrian
283936934Sbrian  throughput_clear(t, clear_type, arg->prompt);
284036934Sbrian  return 0;
284136934Sbrian}
284240561Sbrian
284340561Sbrianstatic int
284440561SbrianRunListCommand(struct cmdargs const *arg)
284540561Sbrian{
284640561Sbrian  const char *cmd = arg->argc ? arg->argv[arg->argc - 1] : "???";
284740561Sbrian
284864801Sbrian#ifndef NONAT
284964801Sbrian  if (arg->cmd->args == NatCommands &&
285064801Sbrian      tolower(*arg->argv[arg->argn - 1]) == 'a') {
285164801Sbrian    if (arg->prompt)
285265550Sbrian      prompt_Printf(arg->prompt, "The alias command is deprecated\n");
285364801Sbrian    else
285465550Sbrian      log_Printf(LogWARN, "The alias command is deprecated\n");
285564801Sbrian  }
285664801Sbrian#endif
285764801Sbrian
285840561Sbrian  if (arg->argc > arg->argn)
285940561Sbrian    FindExec(arg->bundle, arg->cmd->args, arg->argc, arg->argn, arg->argv,
286040561Sbrian             arg->prompt, arg->cx);
286140561Sbrian  else if (arg->prompt)
286240561Sbrian    prompt_Printf(arg->prompt, "Use `%s help' to get a list or `%s help"
286340561Sbrian                  " <option>' for syntax help.\n", cmd, cmd);
286440561Sbrian  else
286540561Sbrian    log_Printf(LogWARN, "%s command must have arguments\n", cmd);
286640561Sbrian
286740561Sbrian  return 0;
286840561Sbrian}
286940561Sbrian
287040561Sbrianstatic int
287140561SbrianIfaceAddCommand(struct cmdargs const *arg)
287240561Sbrian{
287340561Sbrian  int bits, n, how;
287440561Sbrian  struct in_addr ifa, mask, brd;
287540561Sbrian
287640664Sbrian  if (arg->argc == arg->argn + 1) {
287743313Sbrian    if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, NULL, NULL))
287840561Sbrian      return -1;
287940664Sbrian    mask.s_addr = brd.s_addr = INADDR_BROADCAST;
288040664Sbrian  } else {
288140664Sbrian    if (arg->argc == arg->argn + 2) {
288243313Sbrian      if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, &mask, &bits))
288340664Sbrian        return -1;
288440664Sbrian      n = 1;
288540664Sbrian    } else if (arg->argc == arg->argn + 3) {
288643313Sbrian      if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, NULL, NULL))
288740664Sbrian        return -1;
288843313Sbrian      if (!ParseAddr(NULL, arg->argv[arg->argn + 1], &mask, NULL, NULL))
288940664Sbrian        return -1;
289040664Sbrian      n = 2;
289140664Sbrian    } else
289240561Sbrian      return -1;
289340561Sbrian
289443313Sbrian    if (!ParseAddr(NULL, arg->argv[arg->argn + n], &brd, NULL, NULL))
289540664Sbrian      return -1;
289640664Sbrian  }
289740561Sbrian
289840561Sbrian  how = IFACE_ADD_LAST;
289940561Sbrian  if (arg->cmd->args)
290040561Sbrian    how |= IFACE_FORCE_ADD;
290140561Sbrian
290240561Sbrian  return !iface_inAdd(arg->bundle->iface, ifa, mask, brd, how);
290340561Sbrian}
290440561Sbrian
290540561Sbrianstatic int
290640561SbrianIfaceDeleteCommand(struct cmdargs const *arg)
290740561Sbrian{
290840561Sbrian  struct in_addr ifa;
290940561Sbrian  int ok;
291040561Sbrian
291140561Sbrian  if (arg->argc != arg->argn + 1)
291240561Sbrian    return -1;
291340561Sbrian
291443313Sbrian  if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, NULL, NULL))
291540561Sbrian    return -1;
291640561Sbrian
291740561Sbrian  if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED &&
291840561Sbrian      arg->bundle->ncp.ipcp.my_ip.s_addr == ifa.s_addr) {
291940561Sbrian    log_Printf(LogWARN, "%s: Cannot remove active interface address\n",
292040561Sbrian               inet_ntoa(ifa));
292140561Sbrian    return 1;
292240561Sbrian  }
292340561Sbrian
292440561Sbrian  ok = iface_inDelete(arg->bundle->iface, ifa);
292540561Sbrian  if (!ok) {
292640561Sbrian    if (arg->cmd->args)
292740561Sbrian      ok = 1;
292840561Sbrian    else if (arg->prompt)
292940561Sbrian      prompt_Printf(arg->prompt, "%s: No such address\n", inet_ntoa(ifa));
293040561Sbrian    else
293140561Sbrian      log_Printf(LogWARN, "%s: No such address\n", inet_ntoa(ifa));
293240561Sbrian  }
293340561Sbrian
293440561Sbrian  return !ok;
293540561Sbrian}
293640561Sbrian
293740561Sbrianstatic int
293840561SbrianIfaceClearCommand(struct cmdargs const *arg)
293940561Sbrian{
294040561Sbrian  int how;
294140561Sbrian
294240561Sbrian  if (arg->argc != arg->argn)
294340561Sbrian    return -1;
294440561Sbrian
294540941Sbrian  how = arg->bundle->ncp.ipcp.fsm.state == ST_OPENED ||
294640941Sbrian        arg->bundle->phys_type.all & PHYS_AUTO ?
294740561Sbrian        IFACE_CLEAR_ALIASES : IFACE_CLEAR_ALL;
294840561Sbrian  iface_Clear(arg->bundle->iface, how);
294940561Sbrian
295040561Sbrian  return 0;
295140561Sbrian}
295240679Sbrian
295340679Sbrianstatic int
295440679SbrianSetProcTitle(struct cmdargs const *arg)
295540679Sbrian{
295640679Sbrian  static char title[LINE_LEN];
295740679Sbrian  char *argv[MAXARGS], *ptr;
295840679Sbrian  int len, remaining, f, argc = arg->argc - arg->argn;
295940679Sbrian
296040679Sbrian  if (arg->argc == arg->argn) {
296164698Sbrian    SetTitle(NULL);
296240679Sbrian    return 0;
296340679Sbrian  }
296440679Sbrian
296540679Sbrian  if (argc >= sizeof argv / sizeof argv[0]) {
296640679Sbrian    argc = sizeof argv / sizeof argv[0] - 1;
296740679Sbrian    log_Printf(LogWARN, "Truncating proc title to %d args\n", argc);
296840679Sbrian  }
296947849Sbrian  command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 1, getpid());
297040679Sbrian
297140679Sbrian  ptr = title;
297240679Sbrian  remaining = sizeof title - 1;
297340679Sbrian  for (f = 0; f < argc && remaining; f++) {
297440679Sbrian    if (f) {
297540679Sbrian      *ptr++ = ' ';
297640679Sbrian      remaining--;
297740679Sbrian    }
297840679Sbrian    len = strlen(argv[f]);
297940679Sbrian    if (len > remaining)
298040679Sbrian      len = remaining;
298140679Sbrian    memcpy(ptr, argv[f], len);
298240679Sbrian    remaining -= len;
298340679Sbrian    ptr += len;
298440679Sbrian  }
298540679Sbrian  *ptr = '\0';
298640679Sbrian
298764698Sbrian  SetTitle(title);
298840679Sbrian
298940679Sbrian  return 0;
299040679Sbrian}
2991