command.c revision 51048
16059Samurai/*
26059Samurai *		PPP User command processing module
36059Samurai *
46059Samurai *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
56059Samurai *
66059Samurai *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
76059Samurai *
86059Samurai * Redistribution and use in source and binary forms are permitted
96059Samurai * provided that the above copyright notice and this paragraph are
106059Samurai * duplicated in all such forms and that any documentation,
116059Samurai * advertising materials, and other materials related to such
126059Samurai * distribution and use acknowledge that the software was developed
136059Samurai * by the Internet Initiative Japan, Inc.  The name of the
146059Samurai * IIJ may not be used to endorse or promote products derived
156059Samurai * from this software without specific prior written permission.
166059Samurai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
176059Samurai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
186059Samurai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
198857Srgrimes *
2050479Speter * $FreeBSD: head/usr.sbin/ppp/command.c 51048 1999-09-07 07:51:11Z brian $
218857Srgrimes *
226059Samurai */
2343313Sbrian#include <sys/param.h>
2430715Sbrian#include <netinet/in_systm.h>
2526031Sbrian#include <netinet/in.h>
2630715Sbrian#include <netinet/ip.h>
2726031Sbrian#include <arpa/inet.h>
2830715Sbrian#include <sys/socket.h>
2926031Sbrian#include <net/route.h>
3030715Sbrian#include <netdb.h>
3136285Sbrian#include <sys/un.h>
3230715Sbrian
3338628Sbrian#include <ctype.h>
3430715Sbrian#include <errno.h>
3526516Sbrian#include <fcntl.h>
3630715Sbrian#include <paths.h>
3730715Sbrian#include <stdio.h>
3830715Sbrian#include <stdlib.h>
3930715Sbrian#include <string.h>
4030715Sbrian#include <sys/wait.h>
4130715Sbrian#include <termios.h>
4230715Sbrian#include <unistd.h>
4330715Sbrian
4450059Sbrian#ifndef NONAT
4546086Sbrian#ifdef __FreeBSD__
4646086Sbrian#include <alias.h>
4746086Sbrian#else
4839395Sbrian#include "alias.h"
4939395Sbrian#endif
5039395Sbrian#endif
5146686Sbrian#include "layer.h"
5237009Sbrian#include "defs.h"
5331343Sbrian#include "command.h"
5430715Sbrian#include "mbuf.h"
5530715Sbrian#include "log.h"
5630715Sbrian#include "timer.h"
576059Samurai#include "fsm.h"
586059Samurai#include "lcp.h"
5931690Sbrian#include "iplist.h"
6036285Sbrian#include "throughput.h"
6136285Sbrian#include "slcompress.h"
6238557Sbrian#include "lqr.h"
6338557Sbrian#include "hdlc.h"
646059Samurai#include "ipcp.h"
6550059Sbrian#ifndef NONAT
6626031Sbrian#include "alias_cmd.h"
6731343Sbrian#endif
6825630Sbrian#include "systems.h"
6936285Sbrian#include "filter.h"
7036285Sbrian#include "descriptor.h"
7130715Sbrian#include "main.h"
7230715Sbrian#include "route.h"
7330715Sbrian#include "ccp.h"
7431080Sbrian#include "auth.h"
7536285Sbrian#include "async.h"
7636285Sbrian#include "link.h"
7736285Sbrian#include "physical.h"
7836285Sbrian#include "mp.h"
7943313Sbrian#ifndef NORADIUS
8043313Sbrian#include "radius.h"
8143313Sbrian#endif
8236285Sbrian#include "bundle.h"
8336285Sbrian#include "server.h"
8436285Sbrian#include "prompt.h"
8536285Sbrian#include "chat.h"
8636285Sbrian#include "chap.h"
8738174Sbrian#include "cbcp.h"
8836285Sbrian#include "datalink.h"
8940561Sbrian#include "iface.h"
906059Samurai
9136285Sbrian/* ``set'' values */
9236285Sbrian#define	VAR_AUTHKEY	0
9336285Sbrian#define	VAR_DIAL	1
9436285Sbrian#define	VAR_LOGIN	2
9536285Sbrian#define	VAR_AUTHNAME	3
9636285Sbrian#define	VAR_AUTOLOAD	4
9736285Sbrian#define	VAR_WINSIZE	5
9836285Sbrian#define	VAR_DEVICE	6
9936285Sbrian#define	VAR_ACCMAP	7
10036285Sbrian#define	VAR_MRRU	8
10136285Sbrian#define	VAR_MRU		9
10236285Sbrian#define	VAR_MTU		10
10336285Sbrian#define	VAR_OPENMODE	11
10436285Sbrian#define	VAR_PHONE	12
10536285Sbrian#define	VAR_HANGUP	13
10636285Sbrian#define	VAR_IDLETIMEOUT	14
10736285Sbrian#define	VAR_LQRPERIOD	15
10836285Sbrian#define	VAR_LCPRETRY	16
10936285Sbrian#define	VAR_CHAPRETRY	17
11036285Sbrian#define	VAR_PAPRETRY	18
11136285Sbrian#define	VAR_CCPRETRY	19
11236285Sbrian#define	VAR_IPCPRETRY	20
11336285Sbrian#define	VAR_DNS		21
11436285Sbrian#define	VAR_NBNS	22
11536285Sbrian#define	VAR_MODE	23
11638174Sbrian#define	VAR_CALLBACK	24
11738174Sbrian#define	VAR_CBCP	25
11838544Sbrian#define	VAR_CHOKED	26
11940665Sbrian#define	VAR_SENDPIPE	27
12040665Sbrian#define	VAR_RECVPIPE	28
12143313Sbrian#define	VAR_RADIUS	29
12244073Sbrian#define	VAR_CD		30
12346686Sbrian#define	VAR_PARITY	31
12446686Sbrian#define VAR_CRTSCTS	32
12550867Sbrian#define VAR_URGENTPORTS	33
1266059Samurai
12736285Sbrian/* ``accept|deny|disable|enable'' masks */
12836285Sbrian#define NEG_HISMASK (1)
12936285Sbrian#define NEG_MYMASK (2)
13036285Sbrian
13136285Sbrian/* ``accept|deny|disable|enable'' values */
13236285Sbrian#define NEG_ACFCOMP	40
13344106Sbrian#define NEG_CHAP05	41
13444106Sbrian#define NEG_CHAP80	42
13544106Sbrian#define NEG_CHAP80LM	43
13644106Sbrian#define NEG_DEFLATE	44
13747858Sbrian#define NEG_DNS		45
13847858Sbrian#define NEG_ENDDISC	46
13947858Sbrian#define NEG_LQR		47
14047858Sbrian#define NEG_PAP		48
14147858Sbrian#define NEG_PPPDDEFLATE	49
14247858Sbrian#define NEG_PRED1	50
14347858Sbrian#define NEG_PROTOCOMP	51
14447858Sbrian#define NEG_SHORTSEQ	52
14547858Sbrian#define NEG_VJCOMP	53
14636285Sbrian
14749434Sbrianconst char Version[] = "2.23";
14836285Sbrian
14936285Sbrianstatic int ShowCommand(struct cmdargs const *);
15036285Sbrianstatic int TerminalCommand(struct cmdargs const *);
15136285Sbrianstatic int QuitCommand(struct cmdargs const *);
15236285Sbrianstatic int OpenCommand(struct cmdargs const *);
15336285Sbrianstatic int CloseCommand(struct cmdargs const *);
15436285Sbrianstatic int DownCommand(struct cmdargs const *);
15536285Sbrianstatic int SetCommand(struct cmdargs const *);
15636285Sbrianstatic int LinkCommand(struct cmdargs const *);
15736285Sbrianstatic int AddCommand(struct cmdargs const *);
15836285Sbrianstatic int DeleteCommand(struct cmdargs const *);
15936285Sbrianstatic int NegotiateCommand(struct cmdargs const *);
16036934Sbrianstatic int ClearCommand(struct cmdargs const *);
16140561Sbrianstatic int RunListCommand(struct cmdargs const *);
16240561Sbrianstatic int IfaceAddCommand(struct cmdargs const *);
16340561Sbrianstatic int IfaceDeleteCommand(struct cmdargs const *);
16440561Sbrianstatic int IfaceClearCommand(struct cmdargs const *);
16540679Sbrianstatic int SetProcTitle(struct cmdargs const *);
16650059Sbrian#ifndef NONAT
16736285Sbrianstatic int AliasEnable(struct cmdargs const *);
16836285Sbrianstatic int AliasOption(struct cmdargs const *);
16931343Sbrian#endif
1706059Samurai
17136285Sbrianstatic const char *
17236285Sbrianshowcx(struct cmdtab const *cmd)
17336285Sbrian{
17436285Sbrian  if (cmd->lauth & LOCAL_CX)
17536285Sbrian    return "(c)";
17636285Sbrian  else if (cmd->lauth & LOCAL_CX_OPT)
17736285Sbrian    return "(o)";
17836285Sbrian
17936285Sbrian  return "";
18036285Sbrian}
18136285Sbrian
1826059Samuraistatic int
18331343SbrianHelpCommand(struct cmdargs const *arg)
1846059Samurai{
18528679Sbrian  struct cmdtab const *cmd;
18636285Sbrian  int n, cmax, dmax, cols, cxlen;
18736285Sbrian  const char *cx;
1886059Samurai
18936285Sbrian  if (!arg->prompt) {
19036285Sbrian    log_Printf(LogWARN, "help: Cannot help without a prompt\n");
19126516Sbrian    return 0;
19236285Sbrian  }
19326516Sbrian
19436285Sbrian  if (arg->argc > arg->argn) {
19536285Sbrian    for (cmd = arg->cmdtab; cmd->name || cmd->alias; cmd++)
19636285Sbrian      if ((cmd->lauth & arg->prompt->auth) &&
19736285Sbrian          ((cmd->name && !strcasecmp(cmd->name, arg->argv[arg->argn])) ||
19836285Sbrian           (cmd->alias && !strcasecmp(cmd->alias, arg->argv[arg->argn])))) {
19936285Sbrian	prompt_Printf(arg->prompt, "%s %s\n", cmd->syntax, showcx(cmd));
20028679Sbrian	return 0;
2016059Samurai      }
20226516Sbrian    return -1;
2036059Samurai  }
20436285Sbrian
20531372Sbrian  cmax = dmax = 0;
20636285Sbrian  for (cmd = arg->cmdtab; cmd->func; cmd++)
20736285Sbrian    if (cmd->name && (cmd->lauth & arg->prompt->auth)) {
20836285Sbrian      if ((n = strlen(cmd->name) + strlen(showcx(cmd))) > cmax)
20931372Sbrian        cmax = n;
21031372Sbrian      if ((n = strlen(cmd->helpmes)) > dmax)
21131372Sbrian        dmax = n;
21231372Sbrian    }
21331372Sbrian
21431372Sbrian  cols = 80 / (dmax + cmax + 3);
2156059Samurai  n = 0;
21636285Sbrian  prompt_Printf(arg->prompt, "(o) = Optional context,"
21736285Sbrian                " (c) = Context required\n");
21836285Sbrian  for (cmd = arg->cmdtab; cmd->func; cmd++)
21936285Sbrian    if (cmd->name && (cmd->lauth & arg->prompt->auth)) {
22036285Sbrian      cx = showcx(cmd);
22136285Sbrian      cxlen = cmax - strlen(cmd->name);
22240482Sbrian      if (n % cols != 0)
22340482Sbrian        prompt_Printf(arg->prompt, " ");
22440482Sbrian      prompt_Printf(arg->prompt, "%s%-*.*s: %-*.*s",
22536285Sbrian              cmd->name, cxlen, cxlen, cx, dmax, dmax, cmd->helpmes);
22631372Sbrian      if (++n % cols == 0)
22736285Sbrian        prompt_Printf(arg->prompt, "\n");
2286059Samurai    }
22931372Sbrian  if (n % cols != 0)
23036285Sbrian    prompt_Printf(arg->prompt, "\n");
23126516Sbrian
23226516Sbrian  return 0;
2336059Samurai}
2346059Samurai
23536285Sbrianstatic int
23636285SbrianCloneCommand(struct cmdargs const *arg)
2376059Samurai{
23836285Sbrian  char namelist[LINE_LEN];
23936285Sbrian  char *name;
24036285Sbrian  int f;
2416059Samurai
24236285Sbrian  if (arg->argc == arg->argn)
24336285Sbrian    return -1;
24436285Sbrian
24536285Sbrian  namelist[sizeof namelist - 1] = '\0';
24636285Sbrian  for (f = arg->argn; f < arg->argc; f++) {
24736285Sbrian    strncpy(namelist, arg->argv[f], sizeof namelist - 1);
24836285Sbrian    for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
24936285Sbrian      bundle_DatalinkClone(arg->bundle, arg->cx, name);
2506059Samurai  }
25136285Sbrian
25236285Sbrian  return 0;
2536059Samurai}
2546059Samurai
2556059Samuraistatic int
25636285SbrianRemoveCommand(struct cmdargs const *arg)
2576059Samurai{
25836285Sbrian  if (arg->argc != arg->argn)
25936285Sbrian    return -1;
26011336Samurai
26136285Sbrian  if (arg->cx->state != DATALINK_CLOSED) {
26236285Sbrian    log_Printf(LogWARN, "remove: Cannot delete links that aren't closed\n");
26336285Sbrian    return 2;
2646059Samurai  }
26526516Sbrian
26636285Sbrian  bundle_DatalinkRemove(arg->bundle, arg->cx);
26736285Sbrian  return 0;
26836285Sbrian}
26932711Sbrian
27036285Sbrianstatic int
27136285SbrianRenameCommand(struct cmdargs const *arg)
27236285Sbrian{
27336285Sbrian  if (arg->argc != arg->argn + 1)
27436285Sbrian    return -1;
27531121Sbrian
27636285Sbrian  if (bundle_RenameDatalink(arg->bundle, arg->cx, arg->argv[arg->argn]))
27736285Sbrian    return 0;
27836285Sbrian
27936285Sbrian  log_Printf(LogWARN, "%s -> %s: target name already exists\n",
28036285Sbrian             arg->cx->name, arg->argv[arg->argn]);
28136285Sbrian  return 1;
28236285Sbrian}
28336285Sbrian
28436285Sbrianint
28536285SbrianLoadCommand(struct cmdargs const *arg)
28636285Sbrian{
28740797Sbrian  const char *err;
28840797Sbrian  int n, mode;
28936285Sbrian
29040797Sbrian  mode = arg->bundle->phys_type.all;
29136285Sbrian
29240797Sbrian  if (arg->argn < arg->argc) {
29340797Sbrian    for (n = arg->argn; n < arg->argc; n++)
29440797Sbrian      if ((err = system_IsValid(arg->argv[n], arg->prompt, mode)) != NULL) {
29540797Sbrian        log_Printf(LogWARN, "%s: %s\n", arg->argv[n], err);
29640797Sbrian        return 1;
29740797Sbrian      }
29840797Sbrian
29940797Sbrian    for (n = arg->argn; n < arg->argc; n++) {
30040797Sbrian      bundle_SetLabel(arg->bundle, arg->argv[arg->argc - 1]);
30140797Sbrian      system_Select(arg->bundle, arg->argv[n], CONFFILE, arg->prompt, arg->cx);
30240797Sbrian    }
30340797Sbrian    bundle_SetLabel(arg->bundle, arg->argv[arg->argc - 1]);
30440797Sbrian  } else if ((err = system_IsValid("default", arg->prompt, mode)) != NULL) {
30540797Sbrian    log_Printf(LogWARN, "default: %s\n", err);
30636285Sbrian    return 1;
30736285Sbrian  } else {
30840797Sbrian    bundle_SetLabel(arg->bundle, "default");
30940797Sbrian    system_Select(arg->bundle, "default", CONFFILE, arg->prompt, arg->cx);
31040797Sbrian    bundle_SetLabel(arg->bundle, "default");
31136285Sbrian  }
31240797Sbrian
31326516Sbrian  return 0;
3146059Samurai}
3156059Samurai
31636285Sbrianint
31736285SbrianSaveCommand(struct cmdargs const *arg)
31836285Sbrian{
31936285Sbrian  log_Printf(LogWARN, "save command is not implemented (yet).\n");
32036285Sbrian  return 1;
32136285Sbrian}
32236285Sbrian
32310528Samuraistatic int
32436285SbrianDialCommand(struct cmdargs const *arg)
32528536Sbrian{
32636285Sbrian  int res;
32736285Sbrian
32836465Sbrian  if ((arg->cx && !(arg->cx->physical->type & (PHYS_INTERACTIVE|PHYS_AUTO)))
32936465Sbrian      || (!arg->cx &&
33036928Sbrian          (arg->bundle->phys_type.all & ~(PHYS_INTERACTIVE|PHYS_AUTO)))) {
33136285Sbrian    log_Printf(LogWARN, "Manual dial is only available for auto and"
33236285Sbrian              " interactive links\n");
33336285Sbrian    return 1;
33434536Sbrian  }
33536285Sbrian
33636285Sbrian  if (arg->argc > arg->argn && (res = LoadCommand(arg)) != 0)
33736285Sbrian    return res;
33836285Sbrian
33937993Sbrian  bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1);
34036285Sbrian
34136285Sbrian  return 0;
34228536Sbrian}
34328536Sbrian
34438628Sbrian#define isinword(ch) (isalnum(ch) || (ch) == '_')
34538628Sbrian
34638628Sbrianstatic char *
34738628Sbrianstrstrword(char *big, const char *little)
34838628Sbrian{
34938628Sbrian  /* Get the first occurance of the word ``little'' in ``big'' */
35038628Sbrian  char *pos;
35138628Sbrian  int len;
35238628Sbrian
35338628Sbrian  pos = big;
35438628Sbrian  len = strlen(little);
35538628Sbrian
35638628Sbrian  while ((pos = strstr(pos, little)) != NULL)
35747865Sbrian    if ((pos != big && isinword(pos[-1])) || isinword(pos[len]))
35847865Sbrian      pos++;
35947865Sbrian    else if (pos != big && pos[-1] == '\\')
36047865Sbrian      memmove(pos - 1, pos, strlen(pos) + 1);
36147865Sbrian    else
36238628Sbrian      break;
36338628Sbrian
36438628Sbrian  return pos;
36538628Sbrian}
36638628Sbrian
36738628Sbrianstatic char *
36838628Sbriansubst(char *tgt, const char *oldstr, const char *newstr)
36938628Sbrian{
37038628Sbrian  /* tgt is a malloc()d area... realloc() as necessary */
37138628Sbrian  char *word, *ntgt;
37238628Sbrian  int ltgt, loldstr, lnewstr, pos;
37338628Sbrian
37438628Sbrian  if ((word = strstrword(tgt, oldstr)) == NULL)
37538628Sbrian    return tgt;
37638628Sbrian
37738628Sbrian  ltgt = strlen(tgt) + 1;
37838628Sbrian  loldstr = strlen(oldstr);
37938628Sbrian  lnewstr = strlen(newstr);
38038628Sbrian  do {
38138628Sbrian    pos = word - tgt;
38238628Sbrian    if (loldstr > lnewstr)
38338628Sbrian      bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr);
38438628Sbrian    if (loldstr != lnewstr) {
38538628Sbrian      ntgt = realloc(tgt, ltgt += lnewstr - loldstr);
38638628Sbrian      if (ntgt == NULL)
38738628Sbrian        break;			/* Oh wonderful ! */
38838628Sbrian      word = ntgt + pos;
38938628Sbrian      tgt = ntgt;
39038628Sbrian    }
39138628Sbrian    if (lnewstr > loldstr)
39238628Sbrian      bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr);
39338628Sbrian    bcopy(newstr, word, lnewstr);
39438628Sbrian  } while ((word = strstrword(word, oldstr)));
39538628Sbrian
39638628Sbrian  return tgt;
39738628Sbrian}
39838628Sbrian
39943888Sbrianvoid
40043888Sbriancommand_Expand(char **nargv, int argc, char const *const *oargv,
40147849Sbrian               struct bundle *bundle, int inc0, pid_t pid)
40238628Sbrian{
40338628Sbrian  int arg;
40447849Sbrian  char pidstr[12];
40538628Sbrian
40641755Sbrian  if (inc0)
40741755Sbrian    arg = 0;		/* Start at arg 0 */
40841755Sbrian  else {
40941755Sbrian    nargv[0] = strdup(oargv[0]);
41041755Sbrian    arg = 1;
41141755Sbrian  }
41247849Sbrian  snprintf(pidstr, sizeof pidstr, "%d", (int)pid);
41341755Sbrian  for (; arg < argc; arg++) {
41438629Sbrian    nargv[arg] = strdup(oargv[arg]);
41538629Sbrian    nargv[arg] = subst(nargv[arg], "HISADDR",
41638628Sbrian                       inet_ntoa(bundle->ncp.ipcp.peer_ip));
41738629Sbrian    nargv[arg] = subst(nargv[arg], "AUTHNAME", bundle->cfg.auth.name);
41840561Sbrian    nargv[arg] = subst(nargv[arg], "INTERFACE", bundle->iface->name);
41938628Sbrian    nargv[arg] = subst(nargv[arg], "MYADDR", inet_ntoa(bundle->ncp.ipcp.my_ip));
42038629Sbrian    nargv[arg] = subst(nargv[arg], "USER", bundle->ncp.mp.peer.authname);
42138629Sbrian    nargv[arg] = subst(nargv[arg], "PEER_ENDDISC",
42238629Sbrian                       mp_Enddisc(bundle->ncp.mp.peer.enddisc.class,
42338629Sbrian                                  bundle->ncp.mp.peer.enddisc.address,
42438629Sbrian                                  bundle->ncp.mp.peer.enddisc.len));
42538629Sbrian    nargv[arg] = subst(nargv[arg], "ENDDISC",
42638629Sbrian                       mp_Enddisc(bundle->ncp.mp.cfg.enddisc.class,
42738629Sbrian                                  bundle->ncp.mp.cfg.enddisc.address,
42838629Sbrian                                  bundle->ncp.mp.cfg.enddisc.len));
42947849Sbrian    nargv[arg] = subst(nargv[arg], "PROCESSID", pidstr);
43038629Sbrian    nargv[arg] = subst(nargv[arg], "LABEL", bundle_GetLabel(bundle));
43138628Sbrian  }
43238628Sbrian  nargv[arg] = NULL;
43338628Sbrian}
43438628Sbrian
43528536Sbrianstatic int
43631343SbrianShellCommand(struct cmdargs const *arg, int bg)
43710528Samurai{
43810528Samurai  const char *shell;
43947849Sbrian  pid_t shpid, pid;
44020813Sjkh
44118856Ssos#ifdef SHELL_ONLY_INTERACTIVELY
44226911Sbrian  /* we're only allowed to shell when we run ppp interactively */
44336285Sbrian  if (arg->prompt && arg->prompt->owner) {
44436285Sbrian    log_Printf(LogWARN, "Can't start a shell from a network connection\n");
44526516Sbrian    return 1;
44610528Samurai  }
44726911Sbrian#endif
44828679Sbrian
44936285Sbrian  if (arg->argc == arg->argn) {
45036285Sbrian    if (!arg->prompt) {
45136285Sbrian      log_Printf(LogWARN, "Can't start an interactive shell from"
45236285Sbrian                " a config file\n");
45328381Sbrian      return 1;
45436285Sbrian    } else if (arg->prompt->owner) {
45536285Sbrian      log_Printf(LogWARN, "Can't start an interactive shell from"
45636285Sbrian                " a socket connection\n");
45736285Sbrian      return 1;
45828381Sbrian    } else if (bg) {
45936285Sbrian      log_Printf(LogWARN, "Can only start an interactive shell in"
46028679Sbrian		" the foreground mode\n");
46128381Sbrian      return 1;
46228381Sbrian    }
46334536Sbrian  }
46434536Sbrian
46547849Sbrian  pid = getpid();
46628679Sbrian  if ((shpid = fork()) == 0) {
46736285Sbrian    int i, fd;
46818531Sbde
46936285Sbrian    if ((shell = getenv("SHELL")) == 0)
47036285Sbrian      shell = _PATH_BSHELL;
47132017Sbrian
47236285Sbrian    timer_TermService();
47336285Sbrian
47436285Sbrian    if (arg->prompt)
47536285Sbrian      fd = arg->prompt->fd_out;
47636285Sbrian    else if ((fd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
47736285Sbrian      log_Printf(LogALERT, "Failed to open %s: %s\n",
47836285Sbrian                _PATH_DEVNULL, strerror(errno));
47928679Sbrian      exit(1);
48028679Sbrian    }
48149976Sbrian    dup2(fd, STDIN_FILENO);
48249976Sbrian    dup2(fd, STDOUT_FILENO);
48349976Sbrian    dup2(fd, STDERR_FILENO);
48449976Sbrian    for (i = getdtablesize(); i > STDERR_FILENO; i--)
48549976Sbrian      fcntl(i, F_SETFD, 1);
48626516Sbrian
48731061Sbrian    setuid(geteuid());
48836285Sbrian    if (arg->argc > arg->argn) {
48928679Sbrian      /* substitute pseudo args */
49038628Sbrian      char *argv[MAXARGS];
49138628Sbrian      int argc = arg->argc - arg->argn;
49238628Sbrian
49338628Sbrian      if (argc >= sizeof argv / sizeof argv[0]) {
49438628Sbrian        argc = sizeof argv / sizeof argv[0] - 1;
49538628Sbrian        log_Printf(LogWARN, "Truncating shell command to %d args\n", argc);
49631343Sbrian      }
49747849Sbrian      command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 0, pid);
49828679Sbrian      if (bg) {
49928679Sbrian	pid_t p;
50010528Samurai
50128679Sbrian	p = getpid();
50228679Sbrian	if (daemon(1, 1) == -1) {
50336832Sbrian	  log_Printf(LogERROR, "%d: daemon: %s\n", (int)p, strerror(errno));
50428679Sbrian	  exit(1);
50528679Sbrian	}
50636285Sbrian      } else if (arg->prompt)
50736285Sbrian        printf("ppp: Pausing until %s finishes\n", arg->argv[arg->argn]);
50831343Sbrian      execvp(argv[0], argv);
50930316Sbrian    } else {
51036285Sbrian      if (arg->prompt)
51132017Sbrian        printf("ppp: Pausing until %s finishes\n", shell);
51236285Sbrian      prompt_TtyOldMode(arg->prompt);
51331343Sbrian      execl(shell, shell, NULL);
51430316Sbrian    }
51520813Sjkh
51640665Sbrian    log_Printf(LogWARN, "exec() of %s failed: %s\n",
51740665Sbrian              arg->argc > arg->argn ? arg->argv[arg->argn] : shell,
51840665Sbrian              strerror(errno));
51949976Sbrian    _exit(255);
52010528Samurai  }
52136285Sbrian
52236285Sbrian  if (shpid == (pid_t) - 1)
52336285Sbrian    log_Printf(LogERROR, "Fork failed: %s\n", strerror(errno));
52436285Sbrian  else {
52510528Samurai    int status;
52631343Sbrian    waitpid(shpid, &status, 0);
52710528Samurai  }
52820813Sjkh
52936285Sbrian  if (arg->prompt && !arg->prompt->owner)
53036285Sbrian    prompt_TtyCommandMode(arg->prompt);
53120813Sjkh
53236285Sbrian  return 0;
53310528Samurai}
53410528Samurai
53531343Sbrianstatic int
53631343SbrianBgShellCommand(struct cmdargs const *arg)
53731343Sbrian{
53836285Sbrian  if (arg->argc == arg->argn)
53931343Sbrian    return -1;
54031343Sbrian  return ShellCommand(arg, 1);
54131343Sbrian}
54231343Sbrian
54331343Sbrianstatic int
54431343SbrianFgShellCommand(struct cmdargs const *arg)
54531343Sbrian{
54631343Sbrian  return ShellCommand(arg, 0);
54731343Sbrian}
54831343Sbrian
54950059Sbrian#ifndef NONAT
55040561Sbrianstatic struct cmdtab const AliasCommands[] =
55140561Sbrian{
55250059Sbrian  {"addr", NULL, nat_RedirectAddr, LOCAL_AUTH,
55350059Sbrian   "static address translation", "nat addr [addr_local addr_alias]"},
55440561Sbrian  {"deny_incoming", NULL, AliasOption, LOCAL_AUTH,
55550059Sbrian   "stop incoming connections", "nat deny_incoming yes|no",
55640561Sbrian   (const void *) PKT_ALIAS_DENY_INCOMING},
55740561Sbrian  {"enable", NULL, AliasEnable, LOCAL_AUTH,
55850059Sbrian   "enable NAT", "nat enable yes|no"},
55940561Sbrian  {"log", NULL, AliasOption, LOCAL_AUTH,
56050059Sbrian   "log NAT link creation", "nat log yes|no",
56140561Sbrian   (const void *) PKT_ALIAS_LOG},
56250059Sbrian  {"port", NULL, nat_RedirectPort, LOCAL_AUTH, "port redirection",
56350059Sbrian   "nat port proto localaddr:port[-port] aliasport[-aliasport]"},
56450059Sbrian  {"pptp", NULL, nat_Pptp, LOCAL_AUTH,
56550059Sbrian   "Set the PPTP address", "nat pptp IP"},
56650059Sbrian  {"proxy", NULL, nat_ProxyRule, LOCAL_AUTH,
56750059Sbrian   "proxy control", "nat proxy server host[:port] ..."},
56840561Sbrian  {"same_ports", NULL, AliasOption, LOCAL_AUTH,
56950059Sbrian   "try to leave port numbers unchanged", "nat same_ports yes|no",
57040561Sbrian   (const void *) PKT_ALIAS_SAME_PORTS},
57140561Sbrian  {"unregistered_only", NULL, AliasOption, LOCAL_AUTH,
57250059Sbrian   "translate unregistered (private) IP address space only",
57350059Sbrian   "nat unregistered_only yes|no",
57440561Sbrian   (const void *) PKT_ALIAS_UNREGISTERED_ONLY},
57540561Sbrian  {"use_sockets", NULL, AliasOption, LOCAL_AUTH,
57650059Sbrian   "allocate host sockets", "nat use_sockets yes|no",
57740561Sbrian   (const void *) PKT_ALIAS_USE_SOCKETS},
57840561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
57950059Sbrian   "Display this message", "nat help|? [command]", AliasCommands},
58040561Sbrian  {NULL, NULL, NULL},
58140561Sbrian};
58240561Sbrian#endif
58340561Sbrian
58440561Sbrianstatic struct cmdtab const AllowCommands[] = {
58540561Sbrian  {"modes", "mode", AllowModes, LOCAL_AUTH,
58640561Sbrian  "Only allow certain ppp modes", "allow modes mode..."},
58740561Sbrian  {"users", "user", AllowUsers, LOCAL_AUTH,
58840561Sbrian  "Only allow ppp access to certain users", "allow users logname..."},
58940561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
59040561Sbrian  "Display this message", "allow help|? [command]", AllowCommands},
59140561Sbrian  {NULL, NULL, NULL},
59240561Sbrian};
59340561Sbrian
59440561Sbrianstatic struct cmdtab const IfaceCommands[] =
59540561Sbrian{
59640561Sbrian  {"add", NULL, IfaceAddCommand, LOCAL_AUTH,
59740561Sbrian   "Add iface address", "iface add addr[/bits| mask] peer", NULL},
59840561Sbrian  {NULL, "add!", IfaceAddCommand, LOCAL_AUTH,
59940561Sbrian   "Add or change an iface address", "iface add! addr[/bits| mask] peer",
60040561Sbrian   (void *)1},
60140561Sbrian  {"clear", NULL, IfaceClearCommand, LOCAL_AUTH,
60240561Sbrian   "Clear iface address(es)", "iface clear"},
60340561Sbrian  {"delete", "rm", IfaceDeleteCommand, LOCAL_AUTH,
60440561Sbrian   "Delete iface address", "iface delete addr", NULL},
60540561Sbrian  {NULL, "rm!", IfaceDeleteCommand, LOCAL_AUTH,
60640561Sbrian   "Delete iface address", "iface delete addr", (void *)1},
60740561Sbrian  {NULL, "delete!", IfaceDeleteCommand, LOCAL_AUTH,
60840561Sbrian   "Delete iface address", "iface delete addr", (void *)1},
60940561Sbrian  {"show", NULL, iface_Show, LOCAL_AUTH,
61040561Sbrian   "Show iface address(es)", "iface show"},
61140561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
61250059Sbrian   "Display this message", "nat help|? [command]", IfaceCommands},
61340561Sbrian  {NULL, NULL, NULL},
61440561Sbrian};
61540561Sbrian
61630715Sbrianstatic struct cmdtab const Commands[] = {
61736285Sbrian  {"accept", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
61828679Sbrian  "accept option request", "accept option .."},
61928679Sbrian  {"add", NULL, AddCommand, LOCAL_AUTH,
62032109Sbrian  "add route", "add dest mask gateway", NULL},
62136285Sbrian  {NULL, "add!", AddCommand, LOCAL_AUTH,
62232109Sbrian  "add or change route", "add! dest mask gateway", (void *)1},
62340561Sbrian  {"allow", "auth", RunListCommand, LOCAL_AUTH,
62440561Sbrian  "Allow ppp access", "allow users|modes ....", AllowCommands},
62528679Sbrian  {"bg", "!bg", BgShellCommand, LOCAL_AUTH,
62631372Sbrian  "Run a background command", "[!]bg command"},
62736934Sbrian  {"clear", NULL, ClearCommand, LOCAL_AUTH | LOCAL_CX_OPT,
62846686Sbrian  "Clear throughput statistics",
62946686Sbrian  "clear ipcp|physical [current|overall|peak]..."},
63036285Sbrian  {"clone", NULL, CloneCommand, LOCAL_AUTH | LOCAL_CX,
63136285Sbrian  "Clone a link", "clone newname..."},
63236285Sbrian  {"close", NULL, CloseCommand, LOCAL_AUTH | LOCAL_CX_OPT,
63336285Sbrian  "Close an FSM", "close [lcp|ccp]"},
63428679Sbrian  {"delete", NULL, DeleteCommand, LOCAL_AUTH,
63532109Sbrian  "delete route", "delete dest", NULL},
63636285Sbrian  {NULL, "delete!", DeleteCommand, LOCAL_AUTH,
63732109Sbrian  "delete a route if it exists", "delete! dest", (void *)1},
63836285Sbrian  {"deny", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
63928679Sbrian  "Deny option request", "deny option .."},
64036285Sbrian  {"dial", "call", DialCommand, LOCAL_AUTH | LOCAL_CX_OPT,
64140797Sbrian  "Dial and login", "dial|call [system ...]", NULL},
64236285Sbrian  {"disable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
64328679Sbrian  "Disable option", "disable option .."},
64436285Sbrian  {"down", NULL, DownCommand, LOCAL_AUTH | LOCAL_CX_OPT,
64546686Sbrian  "Generate a down event", "down [ccp|lcp]"},
64636285Sbrian  {"enable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
64728679Sbrian  "Enable option", "enable option .."},
64840561Sbrian  {"iface", "interface", RunListCommand, LOCAL_AUTH,
64940561Sbrian  "interface control", "iface option ...", IfaceCommands},
65036285Sbrian  {"link", "datalink", LinkCommand, LOCAL_AUTH,
65136285Sbrian  "Link specific commands", "link name command ..."},
65237008Sbrian  {"load", NULL, LoadCommand, LOCAL_AUTH | LOCAL_CX_OPT,
65340797Sbrian  "Load settings", "load [system ...]"},
65450059Sbrian#ifndef NONAT
65550059Sbrian  {"nat", "alias", RunListCommand, LOCAL_AUTH,
65650059Sbrian  "NAT control", "nat option yes|no", AliasCommands},
65750059Sbrian#endif
65836285Sbrian  {"open", NULL, OpenCommand, LOCAL_AUTH | LOCAL_CX_OPT,
65937955Sbrian  "Open an FSM", "open! [lcp|ccp|ipcp]", (void *)1},
66036285Sbrian  {"passwd", NULL, PasswdCommand, LOCAL_NO_AUTH,
66136285Sbrian  "Password for manipulation", "passwd LocalPassword"},
66236285Sbrian  {"quit", "bye", QuitCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
66336285Sbrian  "Quit PPP program", "quit|bye [all]"},
66436285Sbrian  {"remove", "rm", RemoveCommand, LOCAL_AUTH | LOCAL_CX,
66536285Sbrian  "Remove a link", "remove"},
66636285Sbrian  {"rename", "mv", RenameCommand, LOCAL_AUTH | LOCAL_CX,
66736285Sbrian  "Rename a link", "rename name"},
66828679Sbrian  {"save", NULL, SaveCommand, LOCAL_AUTH,
66928679Sbrian  "Save settings", "save"},
67036285Sbrian  {"set", "setup", SetCommand, LOCAL_AUTH | LOCAL_CX_OPT,
67128679Sbrian  "Set parameters", "set[up] var value"},
67228679Sbrian  {"shell", "!", FgShellCommand, LOCAL_AUTH,
67328679Sbrian  "Run a subshell", "shell|! [sh command]"},
67436285Sbrian  {"show", NULL, ShowCommand, LOCAL_AUTH | LOCAL_CX_OPT,
67531372Sbrian  "Show status and stats", "show var"},
67636285Sbrian  {"term", NULL, TerminalCommand, LOCAL_AUTH | LOCAL_CX,
67731372Sbrian  "Enter terminal mode", "term"},
67828679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
67931343Sbrian  "Display this message", "help|? [command]", Commands},
68028679Sbrian  {NULL, NULL, NULL},
6816059Samurai};
6826059Samurai
68328536Sbrianstatic int
68431343SbrianShowEscape(struct cmdargs const *arg)
6856059Samurai{
68636285Sbrian  if (arg->cx->physical->async.cfg.EscMap[32]) {
68736285Sbrian    int code, bit;
68836285Sbrian    const char *sep = "";
6896059Samurai
69026516Sbrian    for (code = 0; code < 32; code++)
69136285Sbrian      if (arg->cx->physical->async.cfg.EscMap[code])
69228679Sbrian	for (bit = 0; bit < 8; bit++)
69336285Sbrian	  if (arg->cx->physical->async.cfg.EscMap[code] & (1 << bit)) {
69436285Sbrian	    prompt_Printf(arg->prompt, "%s0x%02x", sep, (code << 3) + bit);
69536285Sbrian            sep = ", ";
69636285Sbrian          }
69736285Sbrian    prompt_Printf(arg->prompt, "\n");
6986059Samurai  }
69931077Sbrian  return 0;
7006059Samurai}
7016059Samurai
70228679Sbrianstatic int
70336285SbrianShowTimerList(struct cmdargs const *arg)
7046059Samurai{
70536285Sbrian  timer_Show(0, arg->prompt);
70631077Sbrian  return 0;
7076059Samurai}
7086059Samurai
70928679Sbrianstatic int
71031343SbrianShowStopped(struct cmdargs const *arg)
71128327Sbrian{
71236285Sbrian  prompt_Printf(arg->prompt, " Stopped Timer:  LCP: ");
71336285Sbrian  if (!arg->cx->physical->link.lcp.fsm.StoppedTimer.load)
71436285Sbrian    prompt_Printf(arg->prompt, "Disabled");
71528327Sbrian  else
71636285Sbrian    prompt_Printf(arg->prompt, "%ld secs",
71736285Sbrian                  arg->cx->physical->link.lcp.fsm.StoppedTimer.load / SECTICKS);
71828461Sbrian
71936285Sbrian  prompt_Printf(arg->prompt, ", CCP: ");
72036285Sbrian  if (!arg->cx->physical->link.ccp.fsm.StoppedTimer.load)
72136285Sbrian    prompt_Printf(arg->prompt, "Disabled");
72228461Sbrian  else
72336285Sbrian    prompt_Printf(arg->prompt, "%ld secs",
72436285Sbrian                  arg->cx->physical->link.ccp.fsm.StoppedTimer.load / SECTICKS);
72528461Sbrian
72636285Sbrian  prompt_Printf(arg->prompt, "\n");
72728461Sbrian
72831077Sbrian  return 0;
72928327Sbrian}
73028327Sbrian
73128679Sbrianstatic int
73231343SbrianShowVersion(struct cmdargs const *arg)
7336059Samurai{
73451026Sbrian  prompt_Printf(arg->prompt, "PPP Version %s - %s\n", Version, __DATE__);
73531077Sbrian  return 0;
7366059Samurai}
7376059Samurai
73828679Sbrianstatic int
73936285SbrianShowProtocolStats(struct cmdargs const *arg)
74026326Sbrian{
74136285Sbrian  struct link *l = command_ChooseLink(arg);
74226326Sbrian
74336285Sbrian  prompt_Printf(arg->prompt, "%s:\n", l->name);
74436285Sbrian  link_ReportProtocolStatus(l, arg->prompt);
74531077Sbrian  return 0;
74626326Sbrian}
74726326Sbrian
74830715Sbrianstatic struct cmdtab const ShowCommands[] = {
74936285Sbrian  {"bundle", NULL, bundle_ShowStatus, LOCAL_AUTH,
75036285Sbrian  "bundle details", "show bundle"},
75136285Sbrian  {"ccp", NULL, ccp_ReportStatus, LOCAL_AUTH | LOCAL_CX_OPT,
75236285Sbrian  "CCP status", "show cpp"},
75336285Sbrian  {"compress", NULL, sl_Show, LOCAL_AUTH,
75436285Sbrian  "VJ compression stats", "show compress"},
75536285Sbrian  {"escape", NULL, ShowEscape, LOCAL_AUTH | LOCAL_CX,
75636285Sbrian  "escape characters", "show escape"},
75736285Sbrian  {"filter", NULL, filter_Show, LOCAL_AUTH,
75836285Sbrian  "packet filters", "show filter [in|out|dial|alive]"},
75936285Sbrian  {"hdlc", NULL, hdlc_ReportStatus, LOCAL_AUTH | LOCAL_CX,
76036285Sbrian  "HDLC errors", "show hdlc"},
76140561Sbrian  {"iface", "interface", iface_Show, LOCAL_AUTH,
76240561Sbrian  "Interface status", "show iface"},
76336285Sbrian  {"ipcp", NULL, ipcp_Show, LOCAL_AUTH,
76436285Sbrian  "IPCP status", "show ipcp"},
76547211Sbrian  {"layers", NULL, link_ShowLayers, LOCAL_AUTH | LOCAL_CX_OPT,
76647211Sbrian  "Protocol layers", "show layers"},
76736285Sbrian  {"lcp", NULL, lcp_ReportStatus, LOCAL_AUTH | LOCAL_CX,
76836285Sbrian  "LCP status", "show lcp"},
76936285Sbrian  {"link", "datalink", datalink_Show, LOCAL_AUTH | LOCAL_CX,
77036285Sbrian  "(high-level) link info", "show link"},
77136285Sbrian  {"links", NULL, bundle_ShowLinks, LOCAL_AUTH,
77236285Sbrian  "available link names", "show links"},
77336285Sbrian  {"log", NULL, log_ShowLevel, LOCAL_AUTH,
77436285Sbrian  "log levels", "show log"},
77536285Sbrian  {"mem", NULL, mbuf_Show, LOCAL_AUTH,
77636285Sbrian  "mbuf allocations", "show mem"},
77746686Sbrian  {"physical", NULL, physical_ShowStatus, LOCAL_AUTH | LOCAL_CX,
77846686Sbrian  "(low-level) link info", "show physical"},
77936285Sbrian  {"mp", "multilink", mp_ShowStatus, LOCAL_AUTH,
78036285Sbrian  "multilink setup", "show mp"},
78136285Sbrian  {"proto", NULL, ShowProtocolStats, LOCAL_AUTH | LOCAL_CX_OPT,
78236285Sbrian  "protocol summary", "show proto"},
78336285Sbrian  {"route", NULL, route_Show, LOCAL_AUTH,
78436285Sbrian  "routing table", "show route"},
78536285Sbrian  {"stopped", NULL, ShowStopped, LOCAL_AUTH | LOCAL_CX,
78636285Sbrian  "STOPPED timeout", "show stopped"},
78736285Sbrian  {"timers", NULL, ShowTimerList, LOCAL_AUTH,
78836285Sbrian  "alarm timers", "show timers"},
78928679Sbrian  {"version", NULL, ShowVersion, LOCAL_NO_AUTH | LOCAL_AUTH,
79036285Sbrian  "version string", "show version"},
79136285Sbrian  {"who", NULL, log_ShowWho, LOCAL_AUTH,
79236285Sbrian  "client list", "show who"},
79328679Sbrian  {"help", "?", HelpCommand, LOCAL_NO_AUTH | LOCAL_AUTH,
79431343Sbrian  "Display this message", "show help|? [command]", ShowCommands},
79528679Sbrian  {NULL, NULL, NULL},
7966059Samurai};
7976059Samurai
79830715Sbrianstatic struct cmdtab const *
79931343SbrianFindCommand(struct cmdtab const *cmds, const char *str, int *pmatch)
8006059Samurai{
80126516Sbrian  int nmatch;
80226516Sbrian  int len;
80328679Sbrian  struct cmdtab const *found;
8046059Samurai
80526516Sbrian  found = NULL;
80626516Sbrian  len = strlen(str);
80726516Sbrian  nmatch = 0;
8086059Samurai  while (cmds->func) {
80925566Sbrian    if (cmds->name && strncasecmp(str, cmds->name, len) == 0) {
81026516Sbrian      if (cmds->name[len] == '\0') {
81128679Sbrian	*pmatch = 1;
81228679Sbrian	return cmds;
81326516Sbrian      }
8146059Samurai      nmatch++;
8156059Samurai      found = cmds;
81628679Sbrian    } else if (cmds->alias && strncasecmp(str, cmds->alias, len) == 0) {
81726516Sbrian      if (cmds->alias[len] == '\0') {
81828679Sbrian	*pmatch = 1;
81928679Sbrian	return cmds;
82026516Sbrian      }
8216059Samurai      nmatch++;
8226059Samurai      found = cmds;
8236059Samurai    }
8246059Samurai    cmds++;
8256059Samurai  }
8266059Samurai  *pmatch = nmatch;
82726516Sbrian  return found;
8286059Samurai}
8296059Samurai
83036285Sbrianstatic const char *
83136285SbrianmkPrefix(int argc, char const *const *argv, char *tgt, int sz)
83236285Sbrian{
83336285Sbrian  int f, tlen, len;
83436285Sbrian
83536285Sbrian  tlen = 0;
83636285Sbrian  for (f = 0; f < argc && tlen < sz - 2; f++) {
83736285Sbrian    if (f)
83836285Sbrian      tgt[tlen++] = ' ';
83936285Sbrian    len = strlen(argv[f]);
84036285Sbrian    if (len > sz - tlen - 1)
84136285Sbrian      len = sz - tlen - 1;
84236285Sbrian    strncpy(tgt+tlen, argv[f], len);
84336285Sbrian    tlen += len;
84436285Sbrian  }
84536285Sbrian  tgt[tlen] = '\0';
84636285Sbrian  return tgt;
84736285Sbrian}
84836285Sbrian
84930715Sbrianstatic int
85036285SbrianFindExec(struct bundle *bundle, struct cmdtab const *cmds, int argc, int argn,
85136285Sbrian         char const *const *argv, struct prompt *prompt, struct datalink *cx)
8526059Samurai{
85328679Sbrian  struct cmdtab const *cmd;
8546059Samurai  int val = 1;
8556059Samurai  int nmatch;
85631343Sbrian  struct cmdargs arg;
85736285Sbrian  char prefix[100];
8586059Samurai
85936285Sbrian  cmd = FindCommand(cmds, argv[argn], &nmatch);
8606059Samurai  if (nmatch > 1)
86136285Sbrian    log_Printf(LogWARN, "%s: Ambiguous command\n",
86236285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix));
86336285Sbrian  else if (cmd && (!prompt || (cmd->lauth & prompt->auth))) {
86436285Sbrian    if ((cmd->lauth & LOCAL_CX) && !cx)
86536285Sbrian      /* We've got no context, but we require it */
86636285Sbrian      cx = bundle2datalink(bundle, NULL);
86736285Sbrian
86836285Sbrian    if ((cmd->lauth & LOCAL_CX) && !cx)
86936285Sbrian      log_Printf(LogWARN, "%s: No context (use the `link' command)\n",
87036285Sbrian                mkPrefix(argn+1, argv, prefix, sizeof prefix));
87136285Sbrian    else {
87236285Sbrian      if (cx && !(cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
87336285Sbrian        log_Printf(LogWARN, "%s: Redundant context (%s) ignored\n",
87436285Sbrian                  mkPrefix(argn+1, argv, prefix, sizeof prefix), cx->name);
87536285Sbrian        cx = NULL;
87636285Sbrian      }
87736285Sbrian      arg.cmdtab = cmds;
87836285Sbrian      arg.cmd = cmd;
87936285Sbrian      arg.argc = argc;
88036285Sbrian      arg.argn = argn+1;
88136285Sbrian      arg.argv = argv;
88236285Sbrian      arg.bundle = bundle;
88336285Sbrian      arg.cx = cx;
88436285Sbrian      arg.prompt = prompt;
88536285Sbrian      val = (*cmd->func) (&arg);
88636285Sbrian    }
88731343Sbrian  } else
88836285Sbrian    log_Printf(LogWARN, "%s: Invalid command\n",
88936285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix));
89026516Sbrian
89126516Sbrian  if (val == -1)
89236285Sbrian    log_Printf(LogWARN, "Usage: %s\n", cmd->syntax);
89328679Sbrian  else if (val)
89436285Sbrian    log_Printf(LogWARN, "%s: Failed %d\n",
89536285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix), val);
89626516Sbrian
89726516Sbrian  return val;
8986059Samurai}
8996059Samurai
90037009Sbrianint
90137009Sbriancommand_Interpret(char *buff, int nb, char *argv[MAXARGS])
9026059Samurai{
9036059Samurai  char *cp;
9046059Samurai
9056059Samurai  if (nb > 0) {
9066059Samurai    cp = buff + strcspn(buff, "\r\n");
9076059Samurai    if (cp)
9086059Samurai      *cp = '\0';
90937009Sbrian    return MakeArgs(buff, argv, MAXARGS);
91037009Sbrian  }
91137009Sbrian  return 0;
91231121Sbrian}
9136059Samurai
91431822Sbrianstatic int
91531822Sbrianarghidden(int argc, char const *const *argv, int n)
91631822Sbrian{
91731822Sbrian  /* Is arg n of the given command to be hidden from the log ? */
91831828Sbrian
91931828Sbrian  /* set authkey xxxxx */
92031828Sbrian  /* set key xxxxx */
92131822Sbrian  if (n == 2 && !strncasecmp(argv[0], "se", 2) &&
92231822Sbrian      (!strncasecmp(argv[1], "authk", 5) || !strncasecmp(argv[1], "ke", 2)))
92331822Sbrian    return 1;
92431822Sbrian
92531828Sbrian  /* passwd xxxxx */
92631828Sbrian  if (n == 1 && !strncasecmp(argv[0], "p", 1))
92731828Sbrian    return 1;
92831828Sbrian
92936285Sbrian  /* set server port xxxxx .... */
93036285Sbrian  if (n == 3 && !strncasecmp(argv[0], "se", 2) &&
93136285Sbrian      !strncasecmp(argv[1], "se", 2))
93236285Sbrian    return 1;
93336285Sbrian
93431822Sbrian  return 0;
93531822Sbrian}
93631822Sbrian
93731121Sbrianvoid
93836285Sbriancommand_Run(struct bundle *bundle, int argc, char const *const *argv,
93937008Sbrian           struct prompt *prompt, const char *label, struct datalink *cx)
94031121Sbrian{
94131156Sbrian  if (argc > 0) {
94236285Sbrian    if (log_IsKept(LogCOMMAND)) {
94347844Sbrian      char buf[LINE_LEN];
94431156Sbrian      int f, n;
94531156Sbrian
94631156Sbrian      if (label) {
94731962Sbrian        strncpy(buf, label, sizeof buf - 3);
94831962Sbrian        buf[sizeof buf - 3] = '\0';
94931156Sbrian        strcat(buf, ": ");
95047844Sbrian        n = strlen(buf);
95147844Sbrian      } else {
95247844Sbrian        *buf = '\0';
95347844Sbrian        n = 0;
95431156Sbrian      }
95547844Sbrian      buf[sizeof buf - 1] = '\0';	/* In case we run out of room in buf */
95647844Sbrian
95731156Sbrian      for (f = 0; f < argc; f++) {
95831962Sbrian        if (n < sizeof buf - 1 && f)
95931156Sbrian          buf[n++] = ' ';
96031822Sbrian        if (arghidden(argc, argv, f))
96136285Sbrian          strncpy(buf+n, "********", sizeof buf - n - 1);
96231822Sbrian        else
96331962Sbrian          strncpy(buf+n, argv[f], sizeof buf - n - 1);
96431156Sbrian        n += strlen(buf+n);
96531156Sbrian      }
96636285Sbrian      log_Printf(LogCOMMAND, "%s\n", buf);
96731156Sbrian    }
96837008Sbrian    FindExec(bundle, Commands, argc, 0, argv, prompt, cx);
96931156Sbrian  }
9706059Samurai}
9716059Samurai
97231121Sbrianvoid
97336285Sbriancommand_Decode(struct bundle *bundle, char *buff, int nb, struct prompt *prompt,
97436285Sbrian              const char *label)
97531121Sbrian{
97631121Sbrian  int argc;
97737009Sbrian  char *argv[MAXARGS];
97831121Sbrian
97937009Sbrian  argc = command_Interpret(buff, nb, argv);
98037008Sbrian  command_Run(bundle, argc, (char const *const *)argv, prompt, label, NULL);
98131121Sbrian}
98231121Sbrian
9836059Samuraistatic int
98431343SbrianShowCommand(struct cmdargs const *arg)
9856059Samurai{
98636285Sbrian  if (!arg->prompt)
98736285Sbrian    log_Printf(LogWARN, "show: Cannot show without a prompt\n");
98836285Sbrian  else if (arg->argc > arg->argn)
98936285Sbrian    FindExec(arg->bundle, ShowCommands, arg->argc, arg->argn, arg->argv,
99036285Sbrian             arg->prompt, arg->cx);
9916059Samurai  else
99236285Sbrian    prompt_Printf(arg->prompt, "Use ``show ?'' to get a list.\n");
99326516Sbrian
99426516Sbrian  return 0;
9956059Samurai}
9966059Samurai
9976059Samuraistatic int
99831343SbrianTerminalCommand(struct cmdargs const *arg)
9996059Samurai{
100036285Sbrian  if (!arg->prompt) {
100136285Sbrian    log_Printf(LogWARN, "term: Need a prompt\n");
100226516Sbrian    return 1;
10036059Samurai  }
100436285Sbrian
100536285Sbrian  if (arg->cx->physical->link.lcp.fsm.state > ST_CLOSED) {
100636285Sbrian    prompt_Printf(arg->prompt, "LCP state is [%s]\n",
100736285Sbrian                  State2Nam(arg->cx->physical->link.lcp.fsm.state));
100836285Sbrian    return 1;
10096059Samurai  }
101036285Sbrian
101136285Sbrian  datalink_Up(arg->cx, 0, 0);
101236285Sbrian  prompt_TtyTermMode(arg->prompt, arg->cx);
101336285Sbrian  return 0;
10146059Samurai}
10156059Samurai
10166059Samuraistatic int
101731343SbrianQuitCommand(struct cmdargs const *arg)
10186059Samurai{
101936285Sbrian  if (!arg->prompt || prompt_IsController(arg->prompt) ||
102036285Sbrian      (arg->argc > arg->argn && !strcasecmp(arg->argv[arg->argn], "all") &&
102136285Sbrian       (arg->prompt->auth & LOCAL_AUTH)))
102236285Sbrian    Cleanup(EX_NORMAL);
102336285Sbrian  if (arg->prompt)
102436285Sbrian    prompt_Destroy(arg->prompt, 1);
102526516Sbrian
102626516Sbrian  return 0;
10276059Samurai}
10286059Samurai
10296059Samuraistatic int
103036285SbrianOpenCommand(struct cmdargs const *arg)
10316059Samurai{
103237160Sbrian  if (arg->argc == arg->argn)
103337993Sbrian    bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1);
103437160Sbrian  else if (arg->argc == arg->argn + 1) {
103537160Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp")) {
103637385Sbrian      struct datalink *cx = arg->cx ?
103737385Sbrian        arg->cx : bundle2datalink(arg->bundle, NULL);
103837385Sbrian      if (cx) {
103937385Sbrian        if (cx->physical->link.lcp.fsm.state == ST_OPENED)
104037385Sbrian          fsm_Reopen(&cx->physical->link.lcp.fsm);
104137160Sbrian        else
104237993Sbrian          bundle_Open(arg->bundle, cx->name, PHYS_ALL, 1);
104337160Sbrian      } else
104437160Sbrian        log_Printf(LogWARN, "open lcp: You must specify a link\n");
104537160Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) {
104637160Sbrian      struct fsm *fp;
10476059Samurai
104837210Sbrian      fp = &command_ChooseLink(arg)->ccp.fsm;
104937160Sbrian      if (fp->link->lcp.fsm.state != ST_OPENED)
105037160Sbrian        log_Printf(LogWARN, "open: LCP must be open before opening CCP\n");
105137160Sbrian      else if (fp->state == ST_OPENED)
105237160Sbrian        fsm_Reopen(fp);
105337160Sbrian      else {
105437160Sbrian        fp->open_mode = 0;	/* Not passive any more */
105537160Sbrian        if (fp->state == ST_STOPPED) {
105637160Sbrian          fsm_Down(fp);
105737160Sbrian          fsm_Up(fp);
105837160Sbrian        } else {
105937160Sbrian          fsm_Up(fp);
106037160Sbrian          fsm_Open(fp);
106137160Sbrian        }
106236285Sbrian      }
106337160Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ipcp")) {
106437160Sbrian      if (arg->cx)
106537160Sbrian        log_Printf(LogWARN, "open ipcp: You need not specify a link\n");
106637160Sbrian      if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED)
106737160Sbrian        fsm_Reopen(&arg->bundle->ncp.ipcp.fsm);
106837160Sbrian      else
106937993Sbrian        bundle_Open(arg->bundle, NULL, PHYS_ALL, 1);
107037160Sbrian    } else
107137160Sbrian      return -1;
107236285Sbrian  } else
107336285Sbrian    return -1;
107436285Sbrian
107526516Sbrian  return 0;
10766059Samurai}
10776059Samurai
107825067Sbrianstatic int
107936285SbrianCloseCommand(struct cmdargs const *arg)
10806059Samurai{
108137007Sbrian  if (arg->argc == arg->argn)
108237007Sbrian    bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_STAYDOWN);
108337007Sbrian  else if (arg->argc == arg->argn + 1) {
108437007Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp"))
108537007Sbrian      bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_LCP);
108637007Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "ccp") ||
108737007Sbrian             !strcasecmp(arg->argv[arg->argn], "ccp!")) {
108837007Sbrian      struct fsm *fp;
10896059Samurai
109037210Sbrian      fp = &command_ChooseLink(arg)->ccp.fsm;
109137007Sbrian      if (fp->state == ST_OPENED) {
109237007Sbrian        fsm_Close(fp);
109337007Sbrian        if (arg->argv[arg->argn][3] == '!')
109437007Sbrian          fp->open_mode = 0;		/* Stay ST_CLOSED */
109537007Sbrian        else
109637007Sbrian          fp->open_mode = OPEN_PASSIVE;	/* Wait for the peer to start */
109737007Sbrian      }
109837007Sbrian    } else
109936285Sbrian      return -1;
110036285Sbrian  } else
110136285Sbrian    return -1;
110236285Sbrian
110336285Sbrian  return 0;
11046059Samurai}
11056059Samurai
110625067Sbrianstatic int
110736285SbrianDownCommand(struct cmdargs const *arg)
110811336Samurai{
110937018Sbrian  if (arg->argc == arg->argn) {
111037018Sbrian      if (arg->cx)
111137018Sbrian        datalink_Down(arg->cx, CLOSE_STAYDOWN);
111237018Sbrian      else
111337018Sbrian        bundle_Down(arg->bundle, CLOSE_STAYDOWN);
111437018Sbrian  } else if (arg->argc == arg->argn + 1) {
111537018Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp")) {
111637018Sbrian      if (arg->cx)
111737018Sbrian        datalink_Down(arg->cx, CLOSE_LCP);
111837018Sbrian      else
111937018Sbrian        bundle_Down(arg->bundle, CLOSE_LCP);
112037018Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) {
112137018Sbrian      struct fsm *fp = arg->cx ? &arg->cx->physical->link.ccp.fsm :
112237018Sbrian                                 &arg->bundle->ncp.mp.link.ccp.fsm;
112337060Sbrian      fsm2initial(fp);
112437018Sbrian    } else
112537018Sbrian      return -1;
112636285Sbrian  } else
112736285Sbrian    return -1;
112836285Sbrian
112936285Sbrian  return 0;
113025067Sbrian}
113125067Sbrian
113225067Sbrianstatic int
113336285SbrianSetModemSpeed(struct cmdargs const *arg)
113425067Sbrian{
113536285Sbrian  long speed;
113636285Sbrian  char *end;
113711336Samurai
113836285Sbrian  if (arg->argc > arg->argn && *arg->argv[arg->argn]) {
113936285Sbrian    if (arg->argc > arg->argn+1) {
114036285Sbrian      log_Printf(LogWARN, "SetModemSpeed: Too many arguments");
114136285Sbrian      return -1;
114211336Samurai    }
114336285Sbrian    if (strcasecmp(arg->argv[arg->argn], "sync") == 0) {
114436285Sbrian      physical_SetSync(arg->cx->physical);
114536285Sbrian      return 0;
114636285Sbrian    }
114736285Sbrian    end = NULL;
114836285Sbrian    speed = strtol(arg->argv[arg->argn], &end, 10);
114936285Sbrian    if (*end) {
115036285Sbrian      log_Printf(LogWARN, "SetModemSpeed: Bad argument \"%s\"",
115136285Sbrian                arg->argv[arg->argn]);
115236285Sbrian      return -1;
115336285Sbrian    }
115436285Sbrian    if (physical_SetSpeed(arg->cx->physical, speed))
115536285Sbrian      return 0;
115636285Sbrian    log_Printf(LogWARN, "%s: Invalid speed\n", arg->argv[arg->argn]);
115736285Sbrian  } else
115836285Sbrian    log_Printf(LogWARN, "SetModemSpeed: No speed specified\n");
115924939Sbrian
116026516Sbrian  return -1;
116111336Samurai}
116211336Samurai
116325067Sbrianstatic int
116431343SbrianSetStoppedTimeout(struct cmdargs const *arg)
116528327Sbrian{
116636285Sbrian  struct link *l = &arg->cx->physical->link;
116736285Sbrian
116836285Sbrian  l->lcp.fsm.StoppedTimer.load = 0;
116936285Sbrian  l->ccp.fsm.StoppedTimer.load = 0;
117036285Sbrian  if (arg->argc <= arg->argn+2) {
117136285Sbrian    if (arg->argc > arg->argn) {
117236285Sbrian      l->lcp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn]) * SECTICKS;
117336285Sbrian      if (arg->argc > arg->argn+1)
117436285Sbrian        l->ccp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn+1]) * SECTICKS;
117528461Sbrian    }
117628327Sbrian    return 0;
117728327Sbrian  }
117828327Sbrian  return -1;
117928327Sbrian}
118028327Sbrian
118131081Sbrian#define ismask(x) \
118231081Sbrian  (*x == '0' && strlen(x) == 4 && strspn(x+1, "0123456789.") == 3)
118331081Sbrian
118428327Sbrianstatic int
118531343SbrianSetServer(struct cmdargs const *arg)
118626940Sbrian{
118726940Sbrian  int res = -1;
118826940Sbrian
118936285Sbrian  if (arg->argc > arg->argn && arg->argc < arg->argn+4) {
119031081Sbrian    const char *port, *passwd, *mask;
119131081Sbrian
119231081Sbrian    /* What's what ? */
119336285Sbrian    port = arg->argv[arg->argn];
119436285Sbrian    if (arg->argc == arg->argn + 2) {
119536285Sbrian      passwd = arg->argv[arg->argn+1];
119636285Sbrian      mask = NULL;
119736285Sbrian    } else if (arg->argc == arg->argn + 3) {
119836285Sbrian      passwd = arg->argv[arg->argn+1];
119936285Sbrian      mask = arg->argv[arg->argn+2];
120031081Sbrian      if (!ismask(mask))
120131081Sbrian        return -1;
120236285Sbrian    } else if (strcasecmp(port, "none") == 0) {
120336285Sbrian      if (server_Close(arg->bundle))
120436285Sbrian        log_Printf(LogPHASE, "Disabled server port.\n");
120536285Sbrian      return 0;
120631081Sbrian    } else
120736285Sbrian      return -1;
120831081Sbrian
120936285Sbrian    strncpy(server.passwd, passwd, sizeof server.passwd - 1);
121036285Sbrian    server.passwd[sizeof server.passwd - 1] = '\0';
121131081Sbrian
121236285Sbrian    if (*port == '/') {
121331081Sbrian      mode_t imask;
121436285Sbrian      char *ptr, name[LINE_LEN + 12];
121528679Sbrian
121631081Sbrian      if (mask != NULL) {
121728679Sbrian	unsigned m;
121828679Sbrian
121931081Sbrian	if (sscanf(mask, "%o", &m) == 1)
122031081Sbrian	  imask = m;
122131081Sbrian        else
122231081Sbrian          return -1;
122331081Sbrian      } else
122431081Sbrian        imask = (mode_t)-1;
122536285Sbrian
122636285Sbrian      ptr = strstr(port, "%d");
122736285Sbrian      if (ptr) {
122836285Sbrian        snprintf(name, sizeof name, "%.*s%d%s",
122937210Sbrian                 (int)(ptr - port), port, arg->bundle->unit, ptr + 2);
123036285Sbrian        port = name;
123136285Sbrian      }
123236285Sbrian      res = server_LocalOpen(arg->bundle, port, imask);
123327346Sbrian    } else {
123436285Sbrian      int iport, add = 0;
123528679Sbrian
123631081Sbrian      if (mask != NULL)
123731081Sbrian        return -1;
123828679Sbrian
123936285Sbrian      if (*port == '+') {
124036285Sbrian        port++;
124136285Sbrian        add = 1;
124236285Sbrian      }
124331081Sbrian      if (strspn(port, "0123456789") != strlen(port)) {
124431081Sbrian        struct servent *s;
124531081Sbrian
124631081Sbrian        if ((s = getservbyname(port, "tcp")) == NULL) {
124731081Sbrian	  iport = 0;
124836285Sbrian	  log_Printf(LogWARN, "%s: Invalid port or service\n", port);
124928679Sbrian	} else
125031081Sbrian	  iport = ntohs(s->s_port);
125127346Sbrian      } else
125231081Sbrian        iport = atoi(port);
125336285Sbrian
125436285Sbrian      if (iport) {
125536285Sbrian        if (add)
125636285Sbrian          iport += arg->bundle->unit;
125736285Sbrian        res = server_TcpOpen(arg->bundle, iport);
125836285Sbrian      } else
125936285Sbrian        res = -1;
126027346Sbrian    }
126131081Sbrian  }
126226940Sbrian
126326940Sbrian  return res;
126426940Sbrian}
126526940Sbrian
126626940Sbrianstatic int
126731343SbrianSetEscape(struct cmdargs const *arg)
12686059Samurai{
12696059Samurai  int code;
127036285Sbrian  int argc = arg->argc - arg->argn;
127136285Sbrian  char const *const *argv = arg->argv + arg->argn;
12726059Samurai
12736059Samurai  for (code = 0; code < 33; code++)
127436285Sbrian    arg->cx->physical->async.cfg.EscMap[code] = 0;
127531343Sbrian
12766059Samurai  while (argc-- > 0) {
12776059Samurai    sscanf(*argv++, "%x", &code);
12786059Samurai    code &= 0xff;
127936285Sbrian    arg->cx->physical->async.cfg.EscMap[code >> 3] |= (1 << (code & 7));
128036285Sbrian    arg->cx->physical->async.cfg.EscMap[32] = 1;
12816059Samurai  }
128226516Sbrian  return 0;
12836059Samurai}
12846059Samurai
12856059Samuraistatic int
128631343SbrianSetInterfaceAddr(struct cmdargs const *arg)
12876059Samurai{
128836285Sbrian  struct ipcp *ipcp = &arg->bundle->ncp.ipcp;
128932267Sbrian  const char *hisaddr;
129032267Sbrian
129140561Sbrian  if (arg->argc > arg->argn + 4)
129240561Sbrian    return -1;
129340561Sbrian
129432267Sbrian  hisaddr = NULL;
129544874Sbrian  memset(&ipcp->cfg.my_range, '\0', sizeof ipcp->cfg.my_range);
129644874Sbrian  memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
129736285Sbrian  ipcp->cfg.HaveTriggerAddress = 0;
129836285Sbrian  ipcp->cfg.netmask.s_addr = INADDR_ANY;
129936285Sbrian  iplist_reset(&ipcp->cfg.peer_list);
130028394Sbrian
130136285Sbrian  if (arg->argc > arg->argn) {
130243313Sbrian    if (!ParseAddr(ipcp, arg->argv[arg->argn],
130336285Sbrian                   &ipcp->cfg.my_range.ipaddr, &ipcp->cfg.my_range.mask,
130436285Sbrian                   &ipcp->cfg.my_range.width))
130528679Sbrian      return 1;
130636285Sbrian    if (arg->argc > arg->argn+1) {
130736285Sbrian      hisaddr = arg->argv[arg->argn+1];
130836285Sbrian      if (arg->argc > arg->argn+2) {
130944455Sbrian        ipcp->ifmask = ipcp->cfg.netmask = GetIpAddr(arg->argv[arg->argn+2]);
131036285Sbrian	if (arg->argc > arg->argn+3) {
131136285Sbrian	  ipcp->cfg.TriggerAddress = GetIpAddr(arg->argv[arg->argn+3]);
131236285Sbrian	  ipcp->cfg.HaveTriggerAddress = 1;
13139440Samurai	}
13146059Samurai      }
13156059Samurai    }
13166059Samurai  }
131728394Sbrian
131840561Sbrian  /* 0.0.0.0 means any address (0 bits) */
131936285Sbrian  if (ipcp->cfg.my_range.ipaddr.s_addr == INADDR_ANY) {
132036285Sbrian    ipcp->cfg.my_range.mask.s_addr = INADDR_ANY;
132136285Sbrian    ipcp->cfg.my_range.width = 0;
13226059Samurai  }
132336285Sbrian  ipcp->my_ip.s_addr = ipcp->cfg.my_range.ipaddr.s_addr;
132447648Sbrian  bundle_AdjustFilters(arg->bundle, &ipcp->my_ip, NULL);
132536285Sbrian
132636285Sbrian  if (hisaddr && !ipcp_UseHisaddr(arg->bundle, hisaddr,
132736928Sbrian                                  arg->bundle->phys_type.all & PHYS_AUTO))
132832267Sbrian    return 4;
132931121Sbrian
133026516Sbrian  return 0;
13316059Samurai}
13326059Samurai
133318752Sjkhstatic int
133444305SbrianSetRetry(int argc, char const *const *argv, u_int *timeout, u_int *maxreq,
133544305Sbrian          u_int *maxtrm, int def)
133644305Sbrian{
133744305Sbrian  if (argc == 0) {
133844305Sbrian    *timeout = DEF_FSMRETRY;
133944305Sbrian    *maxreq = def;
134044305Sbrian    if (maxtrm != NULL)
134144305Sbrian      *maxtrm = def;
134244305Sbrian  } else {
134344305Sbrian    long l = atol(argv[0]);
134444305Sbrian
134544305Sbrian    if (l < MIN_FSMRETRY) {
134644305Sbrian      log_Printf(LogWARN, "%ld: Invalid FSM retry period - min %d\n",
134744305Sbrian                 l, MIN_FSMRETRY);
134844305Sbrian      return 1;
134944305Sbrian    } else
135044305Sbrian      *timeout = l;
135144305Sbrian
135244305Sbrian    if (argc > 1) {
135344305Sbrian      l = atol(argv[1]);
135444305Sbrian      if (l < 1) {
135544305Sbrian        log_Printf(LogWARN, "%ld: Invalid FSM REQ tries - changed to 1\n", l);
135644305Sbrian        l = 1;
135744305Sbrian      }
135844305Sbrian      *maxreq = l;
135944305Sbrian
136044305Sbrian      if (argc > 2 && maxtrm != NULL) {
136144305Sbrian        l = atol(argv[2]);
136244305Sbrian        if (l < 1) {
136344305Sbrian          log_Printf(LogWARN, "%ld: Invalid FSM TRM tries - changed to 1\n", l);
136444305Sbrian          l = 1;
136544305Sbrian        }
136644305Sbrian        *maxtrm = l;
136744305Sbrian      }
136844305Sbrian    }
136944305Sbrian  }
137044305Sbrian
137144305Sbrian  return 0;
137244305Sbrian}
137344305Sbrian
137444305Sbrianstatic int
137531343SbrianSetVariable(struct cmdargs const *arg)
13766059Samurai{
137737210Sbrian  long long_val, param = (long)arg->cmd->args;
137851048Sbrian  int mode, dummyint, f, first;
137931343Sbrian  const char *argp;
138036285Sbrian  struct datalink *cx = arg->cx;	/* LOCAL_CX uses this */
138136285Sbrian  const char *err = NULL;
138236285Sbrian  struct link *l = command_ChooseLink(arg);	/* LOCAL_CX_OPT uses this */
138336285Sbrian  struct in_addr dummyaddr, *addr;
13846059Samurai
138536285Sbrian  if (arg->argc > arg->argn)
138636285Sbrian    argp = arg->argv[arg->argn];
138726551Sbrian  else
138831343Sbrian    argp = "";
138926551Sbrian
139036285Sbrian  if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
139136285Sbrian    log_Printf(LogWARN, "set %s: No context (use the `link' command)\n",
139236285Sbrian              arg->cmd->name);
139336285Sbrian    return 1;
139436285Sbrian  } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
139536285Sbrian    log_Printf(LogWARN, "set %s: Redundant context (%s) ignored\n",
139636285Sbrian              arg->cmd->name, cx->name);
139736285Sbrian    cx = NULL;
139836285Sbrian  }
139936285Sbrian
140026551Sbrian  switch (param) {
140128679Sbrian  case VAR_AUTHKEY:
140250139Sbrian    strncpy(arg->bundle->cfg.auth.key, argp,
140350139Sbrian            sizeof arg->bundle->cfg.auth.key - 1);
140450139Sbrian    arg->bundle->cfg.auth.key[sizeof arg->bundle->cfg.auth.key - 1] = '\0';
140528679Sbrian    break;
140637210Sbrian
140728679Sbrian  case VAR_AUTHNAME:
140840622Sbrian    switch (bundle_Phase(arg->bundle)) {
140940622Sbrian      case PHASE_DEAD:
141040622Sbrian      case PHASE_ESTABLISH:
141140622Sbrian        strncpy(arg->bundle->cfg.auth.name, argp,
141240622Sbrian                sizeof arg->bundle->cfg.auth.name - 1);
141340622Sbrian        arg->bundle->cfg.auth.name[sizeof arg->bundle->cfg.auth.name-1] = '\0';
141440622Sbrian        break;
141540622Sbrian      default:
141640622Sbrian        err = "set authname: Only available at phase DEAD/ESTABLISH\n";
141740622Sbrian        log_Printf(LogWARN, err);
141840622Sbrian        break;
141936285Sbrian    }
142028679Sbrian    break;
142137210Sbrian
142236285Sbrian  case VAR_AUTOLOAD:
142349434Sbrian    if (arg->argc == arg->argn + 3) {
142449434Sbrian      int v1, v2, v3;
142549434Sbrian      char *end;
142649434Sbrian
142749434Sbrian      v1 = strtol(arg->argv[arg->argn], &end, 0);
142849434Sbrian      if (v1 < 0 || *end) {
142949434Sbrian        log_Printf(LogWARN, "autoload: %s: Invalid min percentage\n",
143049434Sbrian                   arg->argv[arg->argn]);
143149434Sbrian        return 1;
143236285Sbrian      }
143349434Sbrian
143449434Sbrian      v2 = strtol(arg->argv[arg->argn + 1], &end, 0);
143549434Sbrian      if (v2 < 0 || *end) {
143649434Sbrian        log_Printf(LogWARN, "autoload: %s: Invalid max percentage\n",
143749434Sbrian                   arg->argv[arg->argn + 1]);
143849434Sbrian        return 1;
143949434Sbrian      }
144049434Sbrian      if (v2 < v1) {
144149434Sbrian        v3 = v1;
144249434Sbrian        v1 = v2;
144349434Sbrian        v2 = v3;
144449434Sbrian      }
144549434Sbrian
144649434Sbrian      v3 = strtol(arg->argv[arg->argn + 2], &end, 0);
144749434Sbrian      if (v3 <= 0 || *end) {
144849434Sbrian        log_Printf(LogWARN, "autoload: %s: Invalid throughput period\n",
144949434Sbrian                   arg->argv[arg->argn + 2]);
145049434Sbrian        return 1;
145149434Sbrian      }
145249434Sbrian
145349434Sbrian      arg->bundle->ncp.mp.cfg.autoload.min = v1;
145449434Sbrian      arg->bundle->ncp.mp.cfg.autoload.max = v2;
145549434Sbrian      arg->bundle->ncp.mp.cfg.autoload.period = v3;
145649434Sbrian      mp_RestartAutoloadTimer(&arg->bundle->ncp.mp);
145736285Sbrian    } else {
145849434Sbrian      err = "Set autoload requires three arguments\n";
145936285Sbrian      log_Printf(LogWARN, err);
146036285Sbrian    }
146136285Sbrian    break;
146237210Sbrian
146328679Sbrian  case VAR_DIAL:
146436285Sbrian    strncpy(cx->cfg.script.dial, argp, sizeof cx->cfg.script.dial - 1);
146536285Sbrian    cx->cfg.script.dial[sizeof cx->cfg.script.dial - 1] = '\0';
146628679Sbrian    break;
146737210Sbrian
146828679Sbrian  case VAR_LOGIN:
146936285Sbrian    strncpy(cx->cfg.script.login, argp, sizeof cx->cfg.script.login - 1);
147036285Sbrian    cx->cfg.script.login[sizeof cx->cfg.script.login - 1] = '\0';
147128679Sbrian    break;
147237210Sbrian
147336285Sbrian  case VAR_WINSIZE:
147436285Sbrian    if (arg->argc > arg->argn) {
147536285Sbrian      l->ccp.cfg.deflate.out.winsize = atoi(arg->argv[arg->argn]);
147636285Sbrian      if (l->ccp.cfg.deflate.out.winsize < 8 ||
147736285Sbrian          l->ccp.cfg.deflate.out.winsize > 15) {
147836285Sbrian          log_Printf(LogWARN, "%d: Invalid outgoing window size\n",
147936285Sbrian                    l->ccp.cfg.deflate.out.winsize);
148036285Sbrian          l->ccp.cfg.deflate.out.winsize = 15;
148136285Sbrian      }
148236285Sbrian      if (arg->argc > arg->argn+1) {
148336285Sbrian        l->ccp.cfg.deflate.in.winsize = atoi(arg->argv[arg->argn+1]);
148436285Sbrian        if (l->ccp.cfg.deflate.in.winsize < 8 ||
148536285Sbrian            l->ccp.cfg.deflate.in.winsize > 15) {
148636285Sbrian            log_Printf(LogWARN, "%d: Invalid incoming window size\n",
148736285Sbrian                      l->ccp.cfg.deflate.in.winsize);
148836285Sbrian            l->ccp.cfg.deflate.in.winsize = 15;
148936285Sbrian        }
149036285Sbrian      } else
149136285Sbrian        l->ccp.cfg.deflate.in.winsize = 0;
149236285Sbrian    } else {
149336285Sbrian      err = "No window size specified\n";
149436285Sbrian      log_Printf(LogWARN, err);
149536285Sbrian    }
149636285Sbrian    break;
149737210Sbrian
149828679Sbrian  case VAR_DEVICE:
149936285Sbrian    physical_SetDeviceList(cx->physical, arg->argc - arg->argn,
150036285Sbrian                           arg->argv + arg->argn);
150136285Sbrian    break;
150237210Sbrian
150336285Sbrian  case VAR_ACCMAP:
150436285Sbrian    if (arg->argc > arg->argn) {
150537210Sbrian      u_long ulong_val;
150636285Sbrian      sscanf(argp, "%lx", &ulong_val);
150737210Sbrian      cx->physical->link.lcp.cfg.accmap = (u_int32_t)ulong_val;
150836285Sbrian    } else {
150936285Sbrian      err = "No accmap specified\n";
151036285Sbrian      log_Printf(LogWARN, err);
151136285Sbrian    }
151236285Sbrian    break;
151337210Sbrian
151436285Sbrian  case VAR_MODE:
151536285Sbrian    mode = Nam2mode(argp);
151636285Sbrian    if (mode == PHYS_NONE || mode == PHYS_ALL) {
151736285Sbrian      log_Printf(LogWARN, "%s: Invalid mode\n", argp);
151836285Sbrian      return -1;
151936285Sbrian    }
152036285Sbrian    bundle_SetMode(arg->bundle, cx, mode);
152136285Sbrian    break;
152237210Sbrian
152336285Sbrian  case VAR_MRRU:
152440622Sbrian    switch (bundle_Phase(arg->bundle)) {
152540622Sbrian      case PHASE_DEAD:
152640622Sbrian        break;
152740622Sbrian      case PHASE_ESTABLISH:
152840622Sbrian        /* Make sure none of our links are DATALINK_LCP or greater */
152940622Sbrian        if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) {
153040622Sbrian          log_Printf(LogWARN, "mrru: Only changable before LCP negotiations\n");
153140622Sbrian          return 1;
153240622Sbrian        }
153340622Sbrian        break;
153440622Sbrian      default:
153540622Sbrian        log_Printf(LogWARN, "mrru: Only changable at phase DEAD/ESTABLISH\n");
153640622Sbrian        return 1;
153729696Sbrian    }
153837210Sbrian    long_val = atol(argp);
153937210Sbrian    if (long_val && long_val < MIN_MRU) {
154037210Sbrian      log_Printf(LogWARN, "MRRU %ld: too small - min %d\n", long_val, MIN_MRU);
154137210Sbrian      return 1;
154237210Sbrian    } else if (long_val > MAX_MRU) {
154337210Sbrian      log_Printf(LogWARN, "MRRU %ld: too big - max %d\n", long_val, MAX_MRU);
154437210Sbrian      return 1;
154537210Sbrian    } else
154637210Sbrian      arg->bundle->ncp.mp.cfg.mrru = long_val;
154728679Sbrian    break;
154837210Sbrian
154936285Sbrian  case VAR_MRU:
155037210Sbrian    long_val = atol(argp);
155137210Sbrian    if (long_val == 0)
155237210Sbrian      l->lcp.cfg.mru = DEF_MRU;
155337210Sbrian    else if (long_val < MIN_MRU) {
155437210Sbrian      log_Printf(LogWARN, "MRU %ld: too small - min %d\n", long_val, MIN_MRU);
155537210Sbrian      return 1;
155637210Sbrian    } else if (long_val > MAX_MRU) {
155737210Sbrian      log_Printf(LogWARN, "MRU %ld: too big - max %d\n", long_val, MAX_MRU);
155837210Sbrian      return 1;
155937210Sbrian    } else
156037210Sbrian      l->lcp.cfg.mru = long_val;
156128679Sbrian    break;
156237210Sbrian
156336285Sbrian  case VAR_MTU:
156437210Sbrian    long_val = atol(argp);
156537210Sbrian    if (long_val && long_val < MIN_MTU) {
156637210Sbrian      log_Printf(LogWARN, "MTU %ld: too small - min %d\n", long_val, MIN_MTU);
156737210Sbrian      return 1;
156837210Sbrian    } else if (long_val > MAX_MTU) {
156937210Sbrian      log_Printf(LogWARN, "MTU %ld: too big - max %d\n", long_val, MAX_MTU);
157037210Sbrian      return 1;
157137210Sbrian    } else
157237210Sbrian      arg->bundle->cfg.mtu = long_val;
157336285Sbrian    break;
157437210Sbrian
157536285Sbrian  case VAR_OPENMODE:
157636285Sbrian    if (strcasecmp(argp, "active") == 0)
157736285Sbrian      cx->physical->link.lcp.cfg.openmode = arg->argc > arg->argn+1 ?
157836285Sbrian        atoi(arg->argv[arg->argn+1]) : 1;
157936285Sbrian    else if (strcasecmp(argp, "passive") == 0)
158036285Sbrian      cx->physical->link.lcp.cfg.openmode = OPEN_PASSIVE;
158136285Sbrian    else {
158236285Sbrian      err = "%s: Invalid openmode\n";
158336285Sbrian      log_Printf(LogWARN, err, argp);
158436285Sbrian    }
158536285Sbrian    break;
158637210Sbrian
158728679Sbrian  case VAR_PHONE:
158836285Sbrian    strncpy(cx->cfg.phone.list, argp, sizeof cx->cfg.phone.list - 1);
158936285Sbrian    cx->cfg.phone.list[sizeof cx->cfg.phone.list - 1] = '\0';
159038174Sbrian    cx->phone.alt = cx->phone.next = NULL;
159128679Sbrian    break;
159237210Sbrian
159328679Sbrian  case VAR_HANGUP:
159436285Sbrian    strncpy(cx->cfg.script.hangup, argp, sizeof cx->cfg.script.hangup - 1);
159536285Sbrian    cx->cfg.script.hangup[sizeof cx->cfg.script.hangup - 1] = '\0';
159628679Sbrian    break;
159737210Sbrian
159836285Sbrian  case VAR_IDLETIMEOUT:
159949978Sbrian    if (arg->argc > arg->argn+2)
160036285Sbrian      err = "Too many idle timeout values\n";
160149978Sbrian    else if (arg->argc == arg->argn)
160249978Sbrian      err = "Too few idle timeout values\n";
160349978Sbrian    else {
160449978Sbrian      int timeout, min;
160549978Sbrian
160649978Sbrian      timeout = atoi(argp);
160749978Sbrian      min = arg->argc == arg->argn + 2 ? atoi(arg->argv[arg->argn + 1]) : -1;
160849978Sbrian      bundle_SetIdleTimer(arg->bundle, timeout, min);
160949978Sbrian    }
161036285Sbrian    if (err)
161136285Sbrian      log_Printf(LogWARN, err);
161229549Sbrian    break;
161337210Sbrian
161436285Sbrian  case VAR_LQRPERIOD:
161537210Sbrian    long_val = atol(argp);
161637210Sbrian    if (long_val < MIN_LQRPERIOD) {
161737210Sbrian      log_Printf(LogWARN, "%ld: Invalid lqr period - min %d\n",
161837210Sbrian                 long_val, MIN_LQRPERIOD);
161937210Sbrian      return 1;
162036285Sbrian    } else
162137210Sbrian      l->lcp.cfg.lqrperiod = long_val;
162236285Sbrian    break;
162337210Sbrian
162436285Sbrian  case VAR_LCPRETRY:
162544305Sbrian    return SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
162644305Sbrian                    &cx->physical->link.lcp.cfg.fsm.timeout,
162744305Sbrian                    &cx->physical->link.lcp.cfg.fsm.maxreq,
162844305Sbrian                    &cx->physical->link.lcp.cfg.fsm.maxtrm, DEF_FSMTRIES);
162936285Sbrian    break;
163037210Sbrian
163136285Sbrian  case VAR_CHAPRETRY:
163244305Sbrian    return SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
163344305Sbrian                    &cx->chap.auth.cfg.fsm.timeout,
163444305Sbrian                    &cx->chap.auth.cfg.fsm.maxreq, NULL, DEF_FSMAUTHTRIES);
163536285Sbrian    break;
163637210Sbrian
163736285Sbrian  case VAR_PAPRETRY:
163844305Sbrian    return SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
163944305Sbrian                    &cx->pap.cfg.fsm.timeout, &cx->pap.cfg.fsm.maxreq,
164044305Sbrian                    NULL, DEF_FSMAUTHTRIES);
164136285Sbrian    break;
164237210Sbrian
164336285Sbrian  case VAR_CCPRETRY:
164444305Sbrian    return SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
164544305Sbrian                    &l->ccp.cfg.fsm.timeout, &l->ccp.cfg.fsm.maxreq,
164644305Sbrian                    &l->ccp.cfg.fsm.maxtrm, DEF_FSMTRIES);
164736285Sbrian    break;
164837210Sbrian
164936285Sbrian  case VAR_IPCPRETRY:
165044305Sbrian    return SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
165144305Sbrian                    &arg->bundle->ncp.ipcp.cfg.fsm.timeout,
165244305Sbrian                    &arg->bundle->ncp.ipcp.cfg.fsm.maxreq,
165344305Sbrian                    &arg->bundle->ncp.ipcp.cfg.fsm.maxtrm, DEF_FSMTRIES);
165436285Sbrian    break;
165537210Sbrian
165636285Sbrian  case VAR_NBNS:
165736285Sbrian  case VAR_DNS:
165836285Sbrian    if (param == VAR_DNS)
165936285Sbrian      addr = arg->bundle->ncp.ipcp.cfg.ns.dns;
166036285Sbrian    else
166136285Sbrian      addr = arg->bundle->ncp.ipcp.cfg.ns.nbns;
166236285Sbrian
166336285Sbrian    addr[0].s_addr = addr[1].s_addr = INADDR_ANY;
166436285Sbrian
166536285Sbrian    if (arg->argc > arg->argn) {
166643313Sbrian      ParseAddr(&arg->bundle->ncp.ipcp, arg->argv[arg->argn],
166736285Sbrian                addr, &dummyaddr, &dummyint);
166836285Sbrian      if (arg->argc > arg->argn+1)
166943313Sbrian        ParseAddr(&arg->bundle->ncp.ipcp, arg->argv[arg->argn + 1],
167036285Sbrian                  addr + 1, &dummyaddr, &dummyint);
167136285Sbrian
167236285Sbrian      if (addr[1].s_addr == INADDR_ANY)
167336285Sbrian        addr[1].s_addr = addr[0].s_addr;
167436285Sbrian      if (addr[0].s_addr == INADDR_ANY)
167536285Sbrian        addr[0].s_addr = addr[1].s_addr;
167636285Sbrian    }
167736285Sbrian    break;
167838174Sbrian
167938174Sbrian  case VAR_CALLBACK:
168038174Sbrian    cx->cfg.callback.opmask = 0;
168138174Sbrian    for (dummyint = arg->argn; dummyint < arg->argc; dummyint++) {
168238174Sbrian      if (!strcasecmp(arg->argv[dummyint], "auth"))
168338174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_AUTH);
168438174Sbrian      else if (!strcasecmp(arg->argv[dummyint], "cbcp"))
168538174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_CBCP);
168638174Sbrian      else if (!strcasecmp(arg->argv[dummyint], "e.164")) {
168738174Sbrian        if (dummyint == arg->argc - 1)
168838174Sbrian          log_Printf(LogWARN, "No E.164 arg (E.164 ignored) !\n");
168938174Sbrian        else {
169038174Sbrian          cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_E164);
169138174Sbrian          strncpy(cx->cfg.callback.msg, arg->argv[++dummyint],
169238174Sbrian                  sizeof cx->cfg.callback.msg - 1);
169338174Sbrian          cx->cfg.callback.msg[sizeof cx->cfg.callback.msg - 1] = '\0';
169438174Sbrian        }
169538174Sbrian      } else if (!strcasecmp(arg->argv[dummyint], "none"))
169638174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_NONE);
169738174Sbrian      else
169838174Sbrian        return -1;
169938174Sbrian    }
170038174Sbrian    if (cx->cfg.callback.opmask == CALLBACK_BIT(CALLBACK_NONE))
170138174Sbrian      cx->cfg.callback.opmask = 0;
170238174Sbrian    break;
170338174Sbrian
170438174Sbrian  case VAR_CBCP:
170538174Sbrian    cx->cfg.cbcp.delay = 0;
170638174Sbrian    *cx->cfg.cbcp.phone = '\0';
170738174Sbrian    cx->cfg.cbcp.fsmretry = DEF_FSMRETRY;
170838174Sbrian    if (arg->argc > arg->argn) {
170938174Sbrian      strncpy(cx->cfg.cbcp.phone, arg->argv[arg->argn],
171038174Sbrian              sizeof cx->cfg.cbcp.phone - 1);
171138174Sbrian      cx->cfg.cbcp.phone[sizeof cx->cfg.cbcp.phone - 1] = '\0';
171238174Sbrian      if (arg->argc > arg->argn + 1) {
171338174Sbrian        cx->cfg.cbcp.delay = atoi(arg->argv[arg->argn + 1]);
171438174Sbrian        if (arg->argc > arg->argn + 2) {
171538174Sbrian          long_val = atol(arg->argv[arg->argn + 2]);
171638174Sbrian          if (long_val < MIN_FSMRETRY)
171738174Sbrian            log_Printf(LogWARN, "%ld: Invalid CBCP FSM retry period - min %d\n",
171838174Sbrian                       long_val, MIN_FSMRETRY);
171938174Sbrian          else
172038174Sbrian            cx->cfg.cbcp.fsmretry = long_val;
172138174Sbrian        }
172238174Sbrian      }
172338174Sbrian    }
172438174Sbrian    break;
172538544Sbrian
172638544Sbrian  case VAR_CHOKED:
172738544Sbrian    arg->bundle->cfg.choked.timeout = atoi(argp);
172838544Sbrian    if (arg->bundle->cfg.choked.timeout <= 0)
172938544Sbrian      arg->bundle->cfg.choked.timeout = CHOKED_TIMEOUT;
173038544Sbrian    break;
173140665Sbrian
173240665Sbrian  case VAR_SENDPIPE:
173340665Sbrian    long_val = atol(argp);
173440665Sbrian    arg->bundle->ncp.ipcp.cfg.sendpipe = long_val;
173540665Sbrian    break;
173640665Sbrian
173740665Sbrian  case VAR_RECVPIPE:
173840665Sbrian    long_val = atol(argp);
173940665Sbrian    arg->bundle->ncp.ipcp.cfg.recvpipe = long_val;
174040665Sbrian    break;
174143313Sbrian
174243313Sbrian#ifndef NORADIUS
174343313Sbrian  case VAR_RADIUS:
174443313Sbrian    if (!*argp)
174543313Sbrian      *arg->bundle->radius.cfg.file = '\0';
174643313Sbrian    else if (access(argp, R_OK)) {
174743313Sbrian      log_Printf(LogWARN, "%s: %s\n", argp, strerror(errno));
174843313Sbrian      return 1;
174943313Sbrian    } else {
175043313Sbrian      strncpy(arg->bundle->radius.cfg.file, argp,
175143313Sbrian              sizeof arg->bundle->radius.cfg.file - 1);
175243313Sbrian      arg->bundle->radius.cfg.file
175343313Sbrian        [sizeof arg->bundle->radius.cfg.file - 1] = '\0';
175443313Sbrian    }
175543313Sbrian    break;
175643313Sbrian#endif
175744073Sbrian
175844073Sbrian  case VAR_CD:
175944073Sbrian    if (*argp) {
176044073Sbrian      long_val = atol(argp);
176144073Sbrian      if (long_val < 0)
176244073Sbrian        long_val = 0;
176344073Sbrian      cx->physical->cfg.cd.delay = long_val;
176444073Sbrian      cx->physical->cfg.cd.required = argp[strlen(argp)-1] == '!';
176544073Sbrian    } else {
176644073Sbrian      cx->physical->cfg.cd.delay = DEF_CDDELAY;
176744073Sbrian      cx->physical->cfg.cd.required = 0;
176844073Sbrian    }
176944073Sbrian    break;
177036285Sbrian
177146686Sbrian  case VAR_PARITY:
177246686Sbrian    if (arg->argc == arg->argn + 1)
177346686Sbrian      return physical_SetParity(arg->cx->physical, argp);
177446686Sbrian    else {
177546686Sbrian      err = "Parity value must be odd, even or none\n";
177646686Sbrian      log_Printf(LogWARN, err);
177746686Sbrian    }
177846686Sbrian    break;
17796059Samurai
178046686Sbrian  case VAR_CRTSCTS:
178146686Sbrian    if (strcasecmp(argp, "on") == 0)
178236285Sbrian      physical_SetRtsCts(arg->cx->physical, 1);
178346686Sbrian    else if (strcasecmp(argp, "off") == 0)
178436285Sbrian      physical_SetRtsCts(arg->cx->physical, 0);
178546686Sbrian    else {
178646686Sbrian      err = "RTS/CTS value must be on or off\n";
178746686Sbrian      log_Printf(LogWARN, err);
178846686Sbrian    }
178946686Sbrian    break;
179050867Sbrian
179150867Sbrian  case VAR_URGENTPORTS:
179251048Sbrian    if (arg->argn == arg->argc) {
179351048Sbrian      ipcp_ClearUrgentTcpPorts(&arg->bundle->ncp.ipcp);
179451048Sbrian      ipcp_ClearUrgentUdpPorts(&arg->bundle->ncp.ipcp);
179551048Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "udp")) {
179651048Sbrian      if (arg->argn == arg->argc - 1)
179751048Sbrian        ipcp_ClearUrgentUdpPorts(&arg->bundle->ncp.ipcp);
179851048Sbrian      else for (f = arg->argn + 1; f < arg->argc; f++)
179951048Sbrian        if (*arg->argv[f] == '+')
180051048Sbrian          ipcp_AddUrgentUdpPort(&arg->bundle->ncp.ipcp, atoi(arg->argv[f] + 1));
180151048Sbrian        else if (*arg->argv[f] == '-')
180251048Sbrian          ipcp_RemoveUrgentUdpPort(&arg->bundle->ncp.ipcp,
180351048Sbrian                                   atoi(arg->argv[f] + 1));
180451048Sbrian        else {
180551048Sbrian          if (f == arg->argn)
180651048Sbrian            ipcp_ClearUrgentUdpPorts(&arg->bundle->ncp.ipcp);
180751048Sbrian          ipcp_AddUrgentUdpPort(&arg->bundle->ncp.ipcp, atoi(arg->argv[f]));
180851048Sbrian        }
180951048Sbrian    } else {
181051048Sbrian      first = arg->argn;
181151048Sbrian      if (!strcasecmp(arg->argv[first], "tcp") && ++first == arg->argc)
181251048Sbrian        ipcp_ClearUrgentTcpPorts(&arg->bundle->ncp.ipcp);
181351048Sbrian
181451048Sbrian      for (f = first; f < arg->argc; f++)
181551048Sbrian        if (*arg->argv[f] == '+')
181651048Sbrian          ipcp_AddUrgentTcpPort(&arg->bundle->ncp.ipcp, atoi(arg->argv[f] + 1));
181751048Sbrian        else if (*arg->argv[f] == '-')
181851048Sbrian          ipcp_RemoveUrgentTcpPort(&arg->bundle->ncp.ipcp,
181951048Sbrian                                   atoi(arg->argv[f] + 1));
182051048Sbrian        else {
182151048Sbrian          if (f == first)
182251048Sbrian            ipcp_ClearUrgentTcpPorts(&arg->bundle->ncp.ipcp);
182351048Sbrian          ipcp_AddUrgentTcpPort(&arg->bundle->ncp.ipcp, atoi(arg->argv[f]));
182451048Sbrian        }
182551048Sbrian    }
182650867Sbrian    break;
182720812Sjkh  }
182846686Sbrian
182946686Sbrian  return err ? 1 : 0;
183020812Sjkh}
183120812Sjkh
183230715Sbrianstatic struct cmdtab const SetCommands[] = {
183336285Sbrian  {"accmap", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
183436285Sbrian  "accmap value", "set accmap hex-value", (const void *)VAR_ACCMAP},
183528679Sbrian  {"authkey", "key", SetVariable, LOCAL_AUTH,
183636285Sbrian  "authentication key", "set authkey|key key", (const void *)VAR_AUTHKEY},
183728679Sbrian  {"authname", NULL, SetVariable, LOCAL_AUTH,
183836285Sbrian  "authentication name", "set authname name", (const void *)VAR_AUTHNAME},
183936285Sbrian  {"autoload", NULL, SetVariable, LOCAL_AUTH,
184036285Sbrian  "auto link [de]activation", "set autoload maxtime maxload mintime minload",
184136285Sbrian  (const void *)VAR_AUTOLOAD},
184250867Sbrian  {"bandwidth", NULL, mp_SetDatalinkBandwidth, LOCAL_AUTH | LOCAL_CX,
184350867Sbrian  "datalink bandwidth", "set bandwidth value"},
184438174Sbrian  {"callback", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
184538174Sbrian  "callback control", "set callback [none|auth|cbcp|"
184638174Sbrian  "E.164 *|number[,number]...]...", (const void *)VAR_CALLBACK},
184738174Sbrian  {"cbcp", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
184838174Sbrian  "CBCP control", "set cbcp [*|phone[,phone...] [delay [timeout]]]",
184938174Sbrian  (const void *)VAR_CBCP},
185044305Sbrian  {"ccpretry", "ccpretries", SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
185144305Sbrian   "CCP retries", "set ccpretry value [attempts]", (const void *)VAR_CCPRETRY},
185244073Sbrian  {"cd", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "Carrier delay requirement",
185344073Sbrian   "set cd value[!]", (const void *)VAR_CD},
185444305Sbrian  {"chapretry", "chapretries", SetVariable, LOCAL_AUTH | LOCAL_CX,
185544305Sbrian   "CHAP retries", "set chapretry value [attempts]",
185644305Sbrian   (const void *)VAR_CHAPRETRY},
185738544Sbrian  {"choked", NULL, SetVariable, LOCAL_AUTH,
185838544Sbrian  "choked timeout", "set choked [secs]", (const void *)VAR_CHOKED},
185946686Sbrian  {"ctsrts", "crtscts", SetVariable, LOCAL_AUTH | LOCAL_CX,
186046686Sbrian   "Use hardware flow control", "set ctsrts [on|off]",
186146686Sbrian   (const char *)VAR_CRTSCTS},
186236285Sbrian  {"deflate", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
186336285Sbrian  "deflate window sizes", "set deflate out-winsize in-winsize",
186436285Sbrian  (const void *) VAR_WINSIZE},
186536285Sbrian  {"device", "line", SetVariable, LOCAL_AUTH | LOCAL_CX,
186646686Sbrian  "physical device name", "set device|line device-name[,device-name]",
186736285Sbrian  (const void *) VAR_DEVICE},
186836285Sbrian  {"dial", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
186936285Sbrian  "dialing script", "set dial chat-script", (const void *) VAR_DIAL},
187036285Sbrian  {"dns", NULL, SetVariable, LOCAL_AUTH, "Domain Name Server",
187136285Sbrian  "set dns pri-addr [sec-addr]", (const void *)VAR_DNS},
187236285Sbrian  {"enddisc", NULL, mp_SetEnddisc, LOCAL_AUTH,
187336285Sbrian  "Endpoint Discriminator", "set enddisc [IP|magic|label|psn value]"},
187436285Sbrian  {"escape", NULL, SetEscape, LOCAL_AUTH | LOCAL_CX,
187536285Sbrian  "escape characters", "set escape hex-digit ..."},
187636285Sbrian  {"filter", NULL, filter_Set, LOCAL_AUTH,
187736285Sbrian  "packet filters", "set filter alive|dial|in|out rule-no permit|deny "
187849388Sbrian  "[src_addr[/width]] [dst_addr[/width]] [tcp|udp|icmp|ospf|igmp "
187948142Sbrian  "[src [lt|eq|gt port]] [dst [lt|eq|gt port]] [estab] [syn] [finrst]]"},
188036285Sbrian  {"hangup", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
188136285Sbrian  "hangup script", "set hangup chat-script", (const void *) VAR_HANGUP},
188236285Sbrian  {"ifaddr", NULL, SetInterfaceAddr, LOCAL_AUTH, "destination address",
188331343Sbrian  "set ifaddr [src-addr [dst-addr [netmask [trg-addr]]]]"},
188444305Sbrian  {"ipcpretry", "ipcpretries", SetVariable, LOCAL_AUTH, "IPCP retries",
188544305Sbrian   "set ipcpretry value [attempts]", (const void *)VAR_IPCPRETRY},
188644305Sbrian  {"lcpretry", "lcpretries", SetVariable, LOCAL_AUTH | LOCAL_CX, "LCP retries",
188744305Sbrian   "set lcpretry value [attempts]", (const void *)VAR_LCPRETRY},
188836712Sbrian  {"log", NULL, log_SetLevel, LOCAL_AUTH, "log level",
188938622Sbrian  "set log [local] [+|-]async|cbcp|ccp|chat|command|connect|debug|hdlc|id0|"
189047699Sbrian  "ipcp|lcp|lqm|phase|physical|sync|tcp/ip|timer|tun..."},
189136285Sbrian  {"login", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
189236285Sbrian  "login script", "set login chat-script", (const void *) VAR_LOGIN},
189336285Sbrian  {"lqrperiod", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
189436285Sbrian  "LQR period", "set lqrperiod value", (const void *)VAR_LQRPERIOD},
189536285Sbrian  {"mode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "mode value",
189636285Sbrian  "set mode interactive|auto|ddial|background", (const void *)VAR_MODE},
189736285Sbrian  {"mrru", NULL, SetVariable, LOCAL_AUTH, "MRRU value",
189836285Sbrian  "set mrru value", (const void *)VAR_MRRU},
189936285Sbrian  {"mru", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
190036285Sbrian  "MRU value", "set mru value", (const void *)VAR_MRU},
190136285Sbrian  {"mtu", NULL, SetVariable, LOCAL_AUTH,
190236285Sbrian  "interface MTU value", "set mtu value", (const void *)VAR_MTU},
190336285Sbrian  {"nbns", NULL, SetVariable, LOCAL_AUTH, "NetBIOS Name Server",
190436285Sbrian  "set nbns pri-addr [sec-addr]", (const void *)VAR_NBNS},
190536285Sbrian  {"openmode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "open mode",
190636285Sbrian  "set openmode active|passive [secs]", (const void *)VAR_OPENMODE},
190744305Sbrian  {"papretry", "papretries", SetVariable, LOCAL_AUTH | LOCAL_CX, "PAP retries",
190844305Sbrian   "set papretry value [attempts]", (const void *)VAR_PAPRETRY},
190946686Sbrian  {"parity", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "serial parity",
191046686Sbrian   "set parity [odd|even|none]", (const void *)VAR_PARITY},
191136285Sbrian  {"phone", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "telephone number(s)",
191236285Sbrian  "set phone phone1[:phone2[...]]", (const void *)VAR_PHONE},
191340679Sbrian  {"proctitle", "title", SetProcTitle, LOCAL_AUTH,
191440679Sbrian  "Process title", "set proctitle [value]"},
191543313Sbrian#ifndef NORADIUS
191643313Sbrian  {"radius", NULL, SetVariable, LOCAL_AUTH,
191743313Sbrian  "RADIUS Config", "set radius cfgfile", (const void *)VAR_RADIUS},
191843313Sbrian#endif
191936285Sbrian  {"reconnect", NULL, datalink_SetReconnect, LOCAL_AUTH | LOCAL_CX,
192036285Sbrian  "Reconnect timeout", "set reconnect value ntries"},
192140665Sbrian  {"recvpipe", NULL, SetVariable, LOCAL_AUTH,
192240665Sbrian  "RECVPIPE value", "set recvpipe value", (const void *)VAR_RECVPIPE},
192336285Sbrian  {"redial", NULL, datalink_SetRedial, LOCAL_AUTH | LOCAL_CX,
192444468Sbrian  "Redial timeout", "set redial secs[+inc[-incmax]][.next] [attempts]"},
192540665Sbrian  {"sendpipe", NULL, SetVariable, LOCAL_AUTH,
192640665Sbrian  "SENDPIPE value", "set sendpipe value", (const void *)VAR_SENDPIPE},
192728679Sbrian  {"server", "socket", SetServer, LOCAL_AUTH,
192836774Sbrian  "server port", "set server|socket TcpPort|LocalName|none password [mask]"},
192936285Sbrian  {"speed", NULL, SetModemSpeed, LOCAL_AUTH | LOCAL_CX,
193046686Sbrian  "physical speed", "set speed value|sync"},
193136285Sbrian  {"stopped", NULL, SetStoppedTimeout, LOCAL_AUTH | LOCAL_CX,
193236285Sbrian  "STOPPED timeouts", "set stopped [LCPseconds [CCPseconds]]"},
193336285Sbrian  {"timeout", NULL, SetVariable, LOCAL_AUTH, "Idle timeout",
193436285Sbrian  "set timeout idletime", (const void *)VAR_IDLETIMEOUT},
193551048Sbrian  {"urgent", NULL, SetVariable, LOCAL_AUTH, "urgent ports",
193651048Sbrian  "set urgent [tcp|udp] [+|-]port...", (const void *)VAR_URGENTPORTS},
193736285Sbrian  {"vj", NULL, ipcp_vjset, LOCAL_AUTH,
193836285Sbrian  "vj values", "set vj slots|slotcomp [value]"},
193928679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
194031343Sbrian  "Display this message", "set help|? [command]", SetCommands},
194128679Sbrian  {NULL, NULL, NULL},
19426059Samurai};
19436059Samurai
19446059Samuraistatic int
194531343SbrianSetCommand(struct cmdargs const *arg)
19466059Samurai{
194736285Sbrian  if (arg->argc > arg->argn)
194836285Sbrian    FindExec(arg->bundle, SetCommands, arg->argc, arg->argn, arg->argv,
194936285Sbrian             arg->prompt, arg->cx);
195036285Sbrian  else if (arg->prompt)
195136285Sbrian    prompt_Printf(arg->prompt, "Use `set ?' to get a list or `set ? <var>' for"
195226516Sbrian	    " syntax help.\n");
19536059Samurai  else
195436285Sbrian    log_Printf(LogWARN, "set command must have arguments\n");
195526516Sbrian
195626516Sbrian  return 0;
19576059Samurai}
19586059Samurai
19596059Samuraistatic int
196031343SbrianAddCommand(struct cmdargs const *arg)
19616059Samurai{
19626059Samurai  struct in_addr dest, gateway, netmask;
196336285Sbrian  int gw, addrs;
19646059Samurai
196536285Sbrian  if (arg->argc != arg->argn+3 && arg->argc != arg->argn+2)
196631598Sbrian    return -1;
196731598Sbrian
196836285Sbrian  addrs = 0;
196936285Sbrian  if (arg->argc == arg->argn+2) {
197036285Sbrian    if (!strcasecmp(arg->argv[arg->argn], "default"))
197136285Sbrian      dest.s_addr = netmask.s_addr = INADDR_ANY;
197231598Sbrian    else {
197336285Sbrian      int width;
197436285Sbrian
197543313Sbrian      if (!ParseAddr(&arg->bundle->ncp.ipcp, arg->argv[arg->argn],
197636285Sbrian	             &dest, &netmask, &width))
197736285Sbrian        return -1;
197836285Sbrian      if (!strncasecmp(arg->argv[arg->argn], "MYADDR", 6))
197936285Sbrian        addrs = ROUTE_DSTMYADDR;
198036285Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "HISADDR", 7))
198136285Sbrian        addrs = ROUTE_DSTHISADDR;
198231598Sbrian    }
198336285Sbrian    gw = 1;
198434536Sbrian  } else {
198536285Sbrian    if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
198636285Sbrian      addrs = ROUTE_DSTMYADDR;
198736285Sbrian      dest = arg->bundle->ncp.ipcp.my_ip;
198836285Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
198936285Sbrian      addrs = ROUTE_DSTHISADDR;
199036285Sbrian      dest = arg->bundle->ncp.ipcp.peer_ip;
199136285Sbrian    } else
199236285Sbrian      dest = GetIpAddr(arg->argv[arg->argn]);
199336285Sbrian    netmask = GetIpAddr(arg->argv[arg->argn+1]);
199431598Sbrian    gw = 2;
19956059Samurai  }
199636285Sbrian
199736285Sbrian  if (strcasecmp(arg->argv[arg->argn+gw], "HISADDR") == 0) {
199836285Sbrian    gateway = arg->bundle->ncp.ipcp.peer_ip;
199936285Sbrian    addrs |= ROUTE_GWHISADDR;
200040561Sbrian  } else
200136285Sbrian    gateway = GetIpAddr(arg->argv[arg->argn+gw]);
200236285Sbrian
200336285Sbrian  if (bundle_SetRoute(arg->bundle, RTM_ADD, dest, gateway, netmask,
200443313Sbrian                  arg->cmd->args ? 1 : 0, (addrs & ROUTE_GWHISADDR) ? 1 : 0)
200543313Sbrian      && addrs != ROUTE_STATIC)
200636285Sbrian    route_Add(&arg->bundle->ncp.ipcp.route, addrs, dest, netmask, gateway);
200736285Sbrian
200831598Sbrian  return 0;
20096059Samurai}
20106059Samurai
20116059Samuraistatic int
201231343SbrianDeleteCommand(struct cmdargs const *arg)
20136059Samurai{
201431598Sbrian  struct in_addr dest, none;
201536285Sbrian  int addrs;
20166059Samurai
201736285Sbrian  if (arg->argc == arg->argn+1) {
201836285Sbrian    if(strcasecmp(arg->argv[arg->argn], "all") == 0) {
201936285Sbrian      route_IfDelete(arg->bundle, 0);
202036285Sbrian      route_DeleteAll(&arg->bundle->ncp.ipcp.route);
202136285Sbrian    } else {
202236285Sbrian      addrs = 0;
202336285Sbrian      if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
202436285Sbrian        dest = arg->bundle->ncp.ipcp.my_ip;
202536285Sbrian        addrs = ROUTE_DSTMYADDR;
202636285Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
202736285Sbrian        dest = arg->bundle->ncp.ipcp.peer_ip;
202836285Sbrian        addrs = ROUTE_DSTHISADDR;
202936285Sbrian      } else {
203044279Sbrian        dest = GetIpAddr(arg->argv[arg->argn]);
203144279Sbrian        if (dest.s_addr == INADDR_NONE) {
203244279Sbrian          log_Printf(LogWARN, "%s: Invalid IP address\n", arg->argv[arg->argn]);
203344279Sbrian          return -1;
203444279Sbrian        }
203536285Sbrian        addrs = ROUTE_STATIC;
203636285Sbrian      }
203731598Sbrian      none.s_addr = INADDR_ANY;
203836285Sbrian      bundle_SetRoute(arg->bundle, RTM_DELETE, dest, none, none,
203937927Sbrian                      arg->cmd->args ? 1 : 0, 0);
204036285Sbrian      route_Delete(&arg->bundle->ncp.ipcp.route, addrs, dest);
204131598Sbrian    }
204234536Sbrian  } else
204326516Sbrian    return -1;
204426516Sbrian
204526516Sbrian  return 0;
20466059Samurai}
20476059Samurai
204850059Sbrian#ifndef NONAT
204926031Sbrianstatic int
205031343SbrianAliasEnable(struct cmdargs const *arg)
205126031Sbrian{
205236285Sbrian  if (arg->argc == arg->argn+1) {
205336285Sbrian    if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
205450059Sbrian      if (!arg->bundle->NatEnabled) {
205546686Sbrian        if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED)
205646686Sbrian          PacketAliasSetAddress(arg->bundle->ncp.ipcp.my_ip);
205750059Sbrian        arg->bundle->NatEnabled = 1;
205846686Sbrian      }
205937191Sbrian      return 0;
206036285Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "no") == 0) {
206150059Sbrian      arg->bundle->NatEnabled = 0;
206240561Sbrian      arg->bundle->cfg.opt &= ~OPT_IFACEALIAS;
206340561Sbrian      /* Don't iface_Clear() - there may be manually configured addresses */
206426516Sbrian      return 0;
206526142Sbrian    }
206635449Sbrian  }
206736285Sbrian
206826516Sbrian  return -1;
206926031Sbrian}
207026031Sbrian
207126031Sbrian
207226031Sbrianstatic int
207331343SbrianAliasOption(struct cmdargs const *arg)
207426031Sbrian{
207538559Sbrian  long param = (long)arg->cmd->args;
207638559Sbrian
207736285Sbrian  if (arg->argc == arg->argn+1) {
207836285Sbrian    if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
207950059Sbrian      if (arg->bundle->NatEnabled) {
208037191Sbrian	PacketAliasSetMode(param, param);
208128679Sbrian	return 0;
208228679Sbrian      }
208350059Sbrian      log_Printf(LogWARN, "nat not enabled\n");
208436285Sbrian    } else if (strcmp(arg->argv[arg->argn], "no") == 0) {
208550059Sbrian      if (arg->bundle->NatEnabled) {
208637191Sbrian	PacketAliasSetMode(0, param);
208728679Sbrian	return 0;
208828679Sbrian      }
208950059Sbrian      log_Printf(LogWARN, "nat not enabled\n");
209028679Sbrian    }
209135449Sbrian  }
209228679Sbrian  return -1;
209326031Sbrian}
209450059Sbrian#endif /* #ifndef NONAT */
209531121Sbrian
209631121Sbrianstatic int
209736285SbrianLinkCommand(struct cmdargs const *arg)
209836285Sbrian{
209936285Sbrian  if (arg->argc > arg->argn+1) {
210036285Sbrian    char namelist[LINE_LEN];
210136285Sbrian    struct datalink *cx;
210236285Sbrian    char *name;
210336285Sbrian    int result = 0;
210436285Sbrian
210536285Sbrian    if (!strcmp(arg->argv[arg->argn], "*")) {
210636285Sbrian      struct datalink *dl;
210736285Sbrian
210836285Sbrian      cx = arg->bundle->links;
210936285Sbrian      while (cx) {
211036285Sbrian        /* Watch it, the command could be a ``remove'' */
211136285Sbrian        dl = cx->next;
211236285Sbrian        FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
211336285Sbrian                 arg->prompt, cx);
211436285Sbrian        for (cx = arg->bundle->links; cx; cx = cx->next)
211536285Sbrian          if (cx == dl)
211636285Sbrian            break;		/* Pointer's still valid ! */
211736285Sbrian      }
211836285Sbrian    } else {
211936285Sbrian      strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
212036285Sbrian      namelist[sizeof namelist - 1] = '\0';
212136285Sbrian      for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
212236285Sbrian        if (!bundle2datalink(arg->bundle, name)) {
212336285Sbrian          log_Printf(LogWARN, "link: %s: Invalid link name\n", name);
212436285Sbrian          return 1;
212536285Sbrian        }
212636285Sbrian
212736285Sbrian      strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
212836285Sbrian      namelist[sizeof namelist - 1] = '\0';
212936285Sbrian      for(name = strtok(namelist, ", "); name; name = strtok(NULL,", ")) {
213036285Sbrian        cx = bundle2datalink(arg->bundle, name);
213136285Sbrian        if (cx)
213236285Sbrian          FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
213336285Sbrian                   arg->prompt, cx);
213436285Sbrian        else {
213536285Sbrian          log_Printf(LogWARN, "link: %s: Invalidated link name !\n", name);
213636285Sbrian          result++;
213736285Sbrian        }
213836285Sbrian      }
213936285Sbrian    }
214036285Sbrian    return result;
214136285Sbrian  }
214236285Sbrian
214336285Sbrian  log_Printf(LogWARN, "Usage: %s\n", arg->cmd->syntax);
214436285Sbrian  return 2;
214536285Sbrian}
214636285Sbrian
214736285Sbrianstruct link *
214836285Sbriancommand_ChooseLink(struct cmdargs const *arg)
214936285Sbrian{
215036285Sbrian  if (arg->cx)
215136285Sbrian    return &arg->cx->physical->link;
215237210Sbrian  else if (!arg->bundle->ncp.mp.cfg.mrru) {
215336285Sbrian    struct datalink *dl = bundle2datalink(arg->bundle, NULL);
215437210Sbrian    if (dl)
215537210Sbrian      return &dl->physical->link;
215636285Sbrian  }
215737210Sbrian  return &arg->bundle->ncp.mp.link;
215836285Sbrian}
215936285Sbrian
216036285Sbrianstatic const char *
216136285Sbrianident_cmd(const char *cmd, unsigned *keep, unsigned *add)
216236285Sbrian{
216336285Sbrian  const char *result;
216436285Sbrian
216536285Sbrian  switch (*cmd) {
216636285Sbrian    case 'A':
216736285Sbrian    case 'a':
216836285Sbrian      result = "accept";
216936285Sbrian      *keep = NEG_MYMASK;
217036285Sbrian      *add = NEG_ACCEPTED;
217136285Sbrian      break;
217236285Sbrian    case 'D':
217336285Sbrian    case 'd':
217436285Sbrian      switch (cmd[1]) {
217536285Sbrian        case 'E':
217636285Sbrian        case 'e':
217736285Sbrian          result = "deny";
217836285Sbrian          *keep = NEG_MYMASK;
217936285Sbrian          *add = 0;
218036285Sbrian          break;
218136285Sbrian        case 'I':
218236285Sbrian        case 'i':
218336285Sbrian          result = "disable";
218436285Sbrian          *keep = NEG_HISMASK;
218536285Sbrian          *add = 0;
218636285Sbrian          break;
218736285Sbrian        default:
218836285Sbrian          return NULL;
218936285Sbrian      }
219036285Sbrian      break;
219136285Sbrian    case 'E':
219236285Sbrian    case 'e':
219336285Sbrian      result = "enable";
219436285Sbrian      *keep = NEG_HISMASK;
219536285Sbrian      *add = NEG_ENABLED;
219636285Sbrian      break;
219736285Sbrian    default:
219836285Sbrian      return NULL;
219936285Sbrian  }
220036285Sbrian
220136285Sbrian  return result;
220236285Sbrian}
220336285Sbrian
220436285Sbrianstatic int
220536285SbrianOptSet(struct cmdargs const *arg)
220636285Sbrian{
220737574Sbrian  int bit = (int)(long)arg->cmd->args;
220836285Sbrian  const char *cmd;
220936285Sbrian  unsigned keep;			/* Keep these bits */
221036285Sbrian  unsigned add;				/* Add these bits */
221136285Sbrian
221236285Sbrian  if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL)
221336285Sbrian    return 1;
221436285Sbrian
221536285Sbrian  if (add)
221636285Sbrian    arg->bundle->cfg.opt |= bit;
221736285Sbrian  else
221836285Sbrian    arg->bundle->cfg.opt &= ~bit;
221936285Sbrian  return 0;
222036285Sbrian}
222136285Sbrian
222236285Sbrianstatic int
222340561SbrianIfaceAliasOptSet(struct cmdargs const *arg)
222440561Sbrian{
222540561Sbrian  unsigned save = arg->bundle->cfg.opt;
222640561Sbrian  int result = OptSet(arg);
222740561Sbrian
222840561Sbrian  if (result == 0)
222950059Sbrian    if (Enabled(arg->bundle, OPT_IFACEALIAS) && !arg->bundle->NatEnabled) {
223040561Sbrian      arg->bundle->cfg.opt = save;
223150059Sbrian      log_Printf(LogWARN, "Cannot enable iface-alias without NAT\n");
223240561Sbrian      result = 2;
223340561Sbrian    }
223440561Sbrian
223540561Sbrian  return result;
223640561Sbrian}
223740561Sbrian
223840561Sbrianstatic int
223936285SbrianNegotiateSet(struct cmdargs const *arg)
224036285Sbrian{
224137210Sbrian  long param = (long)arg->cmd->args;
224236285Sbrian  struct link *l = command_ChooseLink(arg);	/* LOCAL_CX_OPT uses this */
224336285Sbrian  struct datalink *cx = arg->cx;	/* LOCAL_CX uses this */
224436285Sbrian  const char *cmd;
224536285Sbrian  unsigned keep;			/* Keep these bits */
224636285Sbrian  unsigned add;				/* Add these bits */
224736285Sbrian
224836285Sbrian  if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL)
224936285Sbrian    return 1;
225036285Sbrian
225136285Sbrian  if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
225236285Sbrian    log_Printf(LogWARN, "%s %s: No context (use the `link' command)\n",
225336285Sbrian              cmd, arg->cmd->name);
225436285Sbrian    return 2;
225536285Sbrian  } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
225636285Sbrian    log_Printf(LogWARN, "%s %s: Redundant context (%s) ignored\n",
225736285Sbrian              cmd, arg->cmd->name, cx->name);
225836285Sbrian    cx = NULL;
225936285Sbrian  }
226036285Sbrian
226136285Sbrian  switch (param) {
226236285Sbrian    case NEG_ACFCOMP:
226336285Sbrian      cx->physical->link.lcp.cfg.acfcomp &= keep;
226436285Sbrian      cx->physical->link.lcp.cfg.acfcomp |= add;
226536285Sbrian      break;
226644106Sbrian    case NEG_CHAP05:
226744106Sbrian      cx->physical->link.lcp.cfg.chap05 &= keep;
226844106Sbrian      cx->physical->link.lcp.cfg.chap05 |= add;
226936285Sbrian      break;
227044106Sbrian#ifdef HAVE_DES
227144106Sbrian    case NEG_CHAP80:
227244106Sbrian      cx->physical->link.lcp.cfg.chap80nt &= keep;
227344106Sbrian      cx->physical->link.lcp.cfg.chap80nt |= add;
227444106Sbrian      break;
227544106Sbrian    case NEG_CHAP80LM:
227644106Sbrian      cx->physical->link.lcp.cfg.chap80lm &= keep;
227744106Sbrian      cx->physical->link.lcp.cfg.chap80lm |= add;
227844106Sbrian      break;
227944106Sbrian#endif
228036285Sbrian    case NEG_DEFLATE:
228136285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE] &= keep;
228236285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE] |= add;
228336285Sbrian      break;
228436285Sbrian    case NEG_DNS:
228536285Sbrian      arg->bundle->ncp.ipcp.cfg.ns.dns_neg &= keep;
228636285Sbrian      arg->bundle->ncp.ipcp.cfg.ns.dns_neg |= add;
228736285Sbrian      break;
228847858Sbrian    case NEG_ENDDISC:
228947858Sbrian      arg->bundle->ncp.mp.cfg.negenddisc &= keep;
229047858Sbrian      arg->bundle->ncp.mp.cfg.negenddisc |= add;
229147858Sbrian      break;
229236285Sbrian    case NEG_LQR:
229336285Sbrian      cx->physical->link.lcp.cfg.lqr &= keep;
229436285Sbrian      cx->physical->link.lcp.cfg.lqr |= add;
229536285Sbrian      break;
229636285Sbrian    case NEG_PAP:
229736285Sbrian      cx->physical->link.lcp.cfg.pap &= keep;
229836285Sbrian      cx->physical->link.lcp.cfg.pap |= add;
229936285Sbrian      break;
230036285Sbrian    case NEG_PPPDDEFLATE:
230136285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE24] &= keep;
230236285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE24] |= add;
230336285Sbrian      break;
230436285Sbrian    case NEG_PRED1:
230536285Sbrian      l->ccp.cfg.neg[CCP_NEG_PRED1] &= keep;
230636285Sbrian      l->ccp.cfg.neg[CCP_NEG_PRED1] |= add;
230736285Sbrian      break;
230836285Sbrian    case NEG_PROTOCOMP:
230936285Sbrian      cx->physical->link.lcp.cfg.protocomp &= keep;
231036285Sbrian      cx->physical->link.lcp.cfg.protocomp |= add;
231136285Sbrian      break;
231236285Sbrian    case NEG_SHORTSEQ:
231340622Sbrian      switch (bundle_Phase(arg->bundle)) {
231440622Sbrian        case PHASE_DEAD:
231540622Sbrian          break;
231640622Sbrian        case PHASE_ESTABLISH:
231740622Sbrian          /* Make sure none of our links are DATALINK_LCP or greater */
231840622Sbrian          if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) {
231940622Sbrian            log_Printf(LogWARN, "shortseq: Only changable before"
232040622Sbrian                       " LCP negotiations\n");
232140622Sbrian            return 1;
232240622Sbrian          }
232340622Sbrian          break;
232440622Sbrian        default:
232540622Sbrian          log_Printf(LogWARN, "shortseq: Only changable at phase"
232640622Sbrian                     " DEAD/ESTABLISH\n");
232740622Sbrian          return 1;
232836285Sbrian      }
232940622Sbrian      arg->bundle->ncp.mp.cfg.shortseq &= keep;
233040622Sbrian      arg->bundle->ncp.mp.cfg.shortseq |= add;
233136285Sbrian      break;
233236285Sbrian    case NEG_VJCOMP:
233336285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.neg &= keep;
233436285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.neg |= add;
233536285Sbrian      break;
233636285Sbrian  }
233736285Sbrian
233836285Sbrian  return 0;
233936285Sbrian}
234036285Sbrian
234136285Sbrianstatic struct cmdtab const NegotiateCommands[] = {
234236285Sbrian  {"idcheck", NULL, OptSet, LOCAL_AUTH, "Check FSM reply ids",
234336285Sbrian  "disable|enable", (const void *)OPT_IDCHECK},
234440666Sbrian  {"iface-alias", NULL, IfaceAliasOptSet, LOCAL_AUTH,
234540666Sbrian   "retain interface addresses", "disable|enable",
234640666Sbrian   (const void *)OPT_IFACEALIAS},
234747689Sbrian  {"keep-session", NULL, OptSet, LOCAL_AUTH, "Retain device session leader",
234847689Sbrian  "disable|enable", (const void *)OPT_KEEPSESSION},
234936285Sbrian  {"loopback", NULL, OptSet, LOCAL_AUTH, "Loop packets for local iface",
235036285Sbrian  "disable|enable", (const void *)OPT_LOOPBACK},
235136285Sbrian  {"passwdauth", NULL, OptSet, LOCAL_AUTH, "Use passwd file",
235236285Sbrian  "disable|enable", (const void *)OPT_PASSWDAUTH},
235340665Sbrian  {"proxy", NULL, OptSet, LOCAL_AUTH, "Create a proxy ARP entry",
235436285Sbrian  "disable|enable", (const void *)OPT_PROXY},
235540665Sbrian  {"proxyall", NULL, OptSet, LOCAL_AUTH, "Proxy ARP for all remote hosts",
235640665Sbrian  "disable|enable", (const void *)OPT_PROXYALL},
235736285Sbrian  {"sroutes", NULL, OptSet, LOCAL_AUTH, "Use sticky routes",
235836285Sbrian  "disable|enable", (const void *)OPT_SROUTES},
235936285Sbrian  {"throughput", NULL, OptSet, LOCAL_AUTH, "Rolling throughput",
236036285Sbrian  "disable|enable", (const void *)OPT_THROUGHPUT},
236136285Sbrian  {"utmp", NULL, OptSet, LOCAL_AUTH, "Log connections in utmp",
236236285Sbrian  "disable|enable", (const void *)OPT_UTMP},
236336285Sbrian
236447689Sbrian#define OPT_MAX 10	/* accept/deny allowed below and not above */
236536285Sbrian
236636285Sbrian  {"acfcomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
236736285Sbrian  "Address & Control field compression", "accept|deny|disable|enable",
236836285Sbrian  (const void *)NEG_ACFCOMP},
236944106Sbrian  {"chap", "chap05", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
237036285Sbrian  "Challenge Handshake Authentication Protocol", "accept|deny|disable|enable",
237144106Sbrian  (const void *)NEG_CHAP05},
237244106Sbrian#ifdef HAVE_DES
237344106Sbrian  {"mschap", "chap80nt", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
237444106Sbrian  "Microsoft (NT) CHAP", "accept|deny|disable|enable",
237544106Sbrian  (const void *)NEG_CHAP80},
237644106Sbrian  {"LANMan", "chap80lm", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
237744106Sbrian  "Microsoft (NT) CHAP", "accept|deny|disable|enable",
237844106Sbrian  (const void *)NEG_CHAP80LM},
237944106Sbrian#endif
238036285Sbrian  {"deflate", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
238136285Sbrian  "Deflate compression", "accept|deny|disable|enable",
238236285Sbrian  (const void *)NEG_DEFLATE},
238336285Sbrian  {"deflate24", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
238436285Sbrian  "Deflate (type 24) compression", "accept|deny|disable|enable",
238536285Sbrian  (const void *)NEG_PPPDDEFLATE},
238636285Sbrian  {"dns", NULL, NegotiateSet, LOCAL_AUTH,
238736285Sbrian  "DNS specification", "accept|deny|disable|enable", (const void *)NEG_DNS},
238847858Sbrian  {"enddisc", NULL, NegotiateSet, LOCAL_AUTH, "ENDDISC negotiation",
238947858Sbrian  "accept|deny|disable|enable", (const void *)NEG_ENDDISC},
239036285Sbrian  {"lqr", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
239136285Sbrian  "Link Quality Reports", "accept|deny|disable|enable",
239236285Sbrian  (const void *)NEG_LQR},
239336285Sbrian  {"pap", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
239436285Sbrian  "Password Authentication protocol", "accept|deny|disable|enable",
239536285Sbrian  (const void *)NEG_PAP},
239636285Sbrian  {"pred1", "predictor1", NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
239736285Sbrian  "Predictor 1 compression", "accept|deny|disable|enable",
239836285Sbrian  (const void *)NEG_PRED1},
239936285Sbrian  {"protocomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
240036285Sbrian  "Protocol field compression", "accept|deny|disable|enable",
240136285Sbrian  (const void *)NEG_PROTOCOMP},
240236285Sbrian  {"shortseq", NULL, NegotiateSet, LOCAL_AUTH,
240336285Sbrian  "MP Short Sequence Numbers", "accept|deny|disable|enable",
240436285Sbrian  (const void *)NEG_SHORTSEQ},
240536285Sbrian  {"vjcomp", NULL, NegotiateSet, LOCAL_AUTH,
240636285Sbrian  "Van Jacobson header compression", "accept|deny|disable|enable",
240736285Sbrian  (const void *)NEG_VJCOMP},
240836285Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
240936285Sbrian  "Display this message", "accept|deny|disable|enable help|? [value]",
241036285Sbrian  NegotiateCommands},
241136285Sbrian  {NULL, NULL, NULL},
241236285Sbrian};
241336285Sbrian
241436285Sbrianstatic int
241536285SbrianNegotiateCommand(struct cmdargs const *arg)
241636285Sbrian{
241736285Sbrian  if (arg->argc > arg->argn) {
241836285Sbrian    char const *argv[3];
241936285Sbrian    unsigned keep, add;
242036285Sbrian    int n;
242136285Sbrian
242236285Sbrian    if ((argv[0] = ident_cmd(arg->argv[arg->argn-1], &keep, &add)) == NULL)
242336285Sbrian      return -1;
242436285Sbrian    argv[2] = NULL;
242536285Sbrian
242636285Sbrian    for (n = arg->argn; n < arg->argc; n++) {
242736285Sbrian      argv[1] = arg->argv[n];
242836285Sbrian      FindExec(arg->bundle, NegotiateCommands + (keep == NEG_HISMASK ?
242936285Sbrian               0 : OPT_MAX), 2, 1, argv, arg->prompt, arg->cx);
243036285Sbrian    }
243136285Sbrian  } else if (arg->prompt)
243236285Sbrian    prompt_Printf(arg->prompt, "Use `%s ?' to get a list.\n",
243336285Sbrian	    arg->argv[arg->argn-1]);
243436285Sbrian  else
243536285Sbrian    log_Printf(LogWARN, "%s command must have arguments\n",
243636285Sbrian              arg->argv[arg->argn] );
243736285Sbrian
243836285Sbrian  return 0;
243936285Sbrian}
244036285Sbrian
244136285Sbrianconst char *
244236285Sbriancommand_ShowNegval(unsigned val)
244336285Sbrian{
244436285Sbrian  switch (val&3) {
244536285Sbrian    case 1: return "disabled & accepted";
244636285Sbrian    case 2: return "enabled & denied";
244736285Sbrian    case 3: return "enabled & accepted";
244836285Sbrian  }
244936285Sbrian  return "disabled & denied";
245036285Sbrian}
245136934Sbrian
245236934Sbrianstatic int
245336934SbrianClearCommand(struct cmdargs const *arg)
245436934Sbrian{
245536934Sbrian  struct pppThroughput *t;
245636934Sbrian  struct datalink *cx;
245736934Sbrian  int i, clear_type;
245836934Sbrian
245936934Sbrian  if (arg->argc < arg->argn + 1)
246036934Sbrian    return -1;
246136934Sbrian
246246686Sbrian  if (strcasecmp(arg->argv[arg->argn], "physical") == 0) {
246336934Sbrian    cx = arg->cx;
246436934Sbrian    if (!cx)
246536934Sbrian      cx = bundle2datalink(arg->bundle, NULL);
246636934Sbrian    if (!cx) {
246746686Sbrian      log_Printf(LogWARN, "A link must be specified for ``clear physical''\n");
246836934Sbrian      return 1;
246936934Sbrian    }
247036934Sbrian    t = &cx->physical->link.throughput;
247136934Sbrian  } else if (strcasecmp(arg->argv[arg->argn], "ipcp") == 0)
247236934Sbrian    t = &arg->bundle->ncp.ipcp.throughput;
247336934Sbrian  else
247436934Sbrian    return -1;
247536934Sbrian
247636934Sbrian  if (arg->argc > arg->argn + 1) {
247736934Sbrian    clear_type = 0;
247836934Sbrian    for (i = arg->argn + 1; i < arg->argc; i++)
247936934Sbrian      if (strcasecmp(arg->argv[i], "overall") == 0)
248036934Sbrian        clear_type |= THROUGHPUT_OVERALL;
248136934Sbrian      else if (strcasecmp(arg->argv[i], "current") == 0)
248236934Sbrian        clear_type |= THROUGHPUT_CURRENT;
248336934Sbrian      else if (strcasecmp(arg->argv[i], "peak") == 0)
248436934Sbrian        clear_type |= THROUGHPUT_PEAK;
248536934Sbrian      else
248636934Sbrian        return -1;
248736934Sbrian  } else
248836934Sbrian    clear_type = THROUGHPUT_ALL;
248936934Sbrian
249036934Sbrian  throughput_clear(t, clear_type, arg->prompt);
249136934Sbrian  return 0;
249236934Sbrian}
249340561Sbrian
249440561Sbrianstatic int
249540561SbrianRunListCommand(struct cmdargs const *arg)
249640561Sbrian{
249740561Sbrian  const char *cmd = arg->argc ? arg->argv[arg->argc - 1] : "???";
249840561Sbrian
249940561Sbrian  if (arg->argc > arg->argn)
250040561Sbrian    FindExec(arg->bundle, arg->cmd->args, arg->argc, arg->argn, arg->argv,
250140561Sbrian             arg->prompt, arg->cx);
250240561Sbrian  else if (arg->prompt)
250340561Sbrian    prompt_Printf(arg->prompt, "Use `%s help' to get a list or `%s help"
250440561Sbrian                  " <option>' for syntax help.\n", cmd, cmd);
250540561Sbrian  else
250640561Sbrian    log_Printf(LogWARN, "%s command must have arguments\n", cmd);
250740561Sbrian
250840561Sbrian  return 0;
250940561Sbrian}
251040561Sbrian
251140561Sbrianstatic int
251240561SbrianIfaceAddCommand(struct cmdargs const *arg)
251340561Sbrian{
251440561Sbrian  int bits, n, how;
251540561Sbrian  struct in_addr ifa, mask, brd;
251640561Sbrian
251740664Sbrian  if (arg->argc == arg->argn + 1) {
251843313Sbrian    if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, NULL, NULL))
251940561Sbrian      return -1;
252040664Sbrian    mask.s_addr = brd.s_addr = INADDR_BROADCAST;
252140664Sbrian  } else {
252240664Sbrian    if (arg->argc == arg->argn + 2) {
252343313Sbrian      if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, &mask, &bits))
252440664Sbrian        return -1;
252540664Sbrian      n = 1;
252640664Sbrian    } else if (arg->argc == arg->argn + 3) {
252743313Sbrian      if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, NULL, NULL))
252840664Sbrian        return -1;
252943313Sbrian      if (!ParseAddr(NULL, arg->argv[arg->argn + 1], &mask, NULL, NULL))
253040664Sbrian        return -1;
253140664Sbrian      n = 2;
253240664Sbrian    } else
253340561Sbrian      return -1;
253440561Sbrian
253543313Sbrian    if (!ParseAddr(NULL, arg->argv[arg->argn + n], &brd, NULL, NULL))
253640664Sbrian      return -1;
253740664Sbrian  }
253840561Sbrian
253940561Sbrian  how = IFACE_ADD_LAST;
254040561Sbrian  if (arg->cmd->args)
254140561Sbrian    how |= IFACE_FORCE_ADD;
254240561Sbrian
254340561Sbrian  return !iface_inAdd(arg->bundle->iface, ifa, mask, brd, how);
254440561Sbrian}
254540561Sbrian
254640561Sbrianstatic int
254740561SbrianIfaceDeleteCommand(struct cmdargs const *arg)
254840561Sbrian{
254940561Sbrian  struct in_addr ifa;
255040561Sbrian  int ok;
255140561Sbrian
255240561Sbrian  if (arg->argc != arg->argn + 1)
255340561Sbrian    return -1;
255440561Sbrian
255543313Sbrian  if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, NULL, NULL))
255640561Sbrian    return -1;
255740561Sbrian
255840561Sbrian  if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED &&
255940561Sbrian      arg->bundle->ncp.ipcp.my_ip.s_addr == ifa.s_addr) {
256040561Sbrian    log_Printf(LogWARN, "%s: Cannot remove active interface address\n",
256140561Sbrian               inet_ntoa(ifa));
256240561Sbrian    return 1;
256340561Sbrian  }
256440561Sbrian
256540561Sbrian  ok = iface_inDelete(arg->bundle->iface, ifa);
256640561Sbrian  if (!ok) {
256740561Sbrian    if (arg->cmd->args)
256840561Sbrian      ok = 1;
256940561Sbrian    else if (arg->prompt)
257040561Sbrian      prompt_Printf(arg->prompt, "%s: No such address\n", inet_ntoa(ifa));
257140561Sbrian    else
257240561Sbrian      log_Printf(LogWARN, "%s: No such address\n", inet_ntoa(ifa));
257340561Sbrian  }
257440561Sbrian
257540561Sbrian  return !ok;
257640561Sbrian}
257740561Sbrian
257840561Sbrianstatic int
257940561SbrianIfaceClearCommand(struct cmdargs const *arg)
258040561Sbrian{
258140561Sbrian  int how;
258240561Sbrian
258340561Sbrian  if (arg->argc != arg->argn)
258440561Sbrian    return -1;
258540561Sbrian
258640941Sbrian  how = arg->bundle->ncp.ipcp.fsm.state == ST_OPENED ||
258740941Sbrian        arg->bundle->phys_type.all & PHYS_AUTO ?
258840561Sbrian        IFACE_CLEAR_ALIASES : IFACE_CLEAR_ALL;
258940561Sbrian  iface_Clear(arg->bundle->iface, how);
259040561Sbrian
259140561Sbrian  return 0;
259240561Sbrian}
259340679Sbrian
259440679Sbrianstatic int
259540679SbrianSetProcTitle(struct cmdargs const *arg)
259640679Sbrian{
259740679Sbrian  static char title[LINE_LEN];
259840679Sbrian  char *argv[MAXARGS], *ptr;
259940679Sbrian  int len, remaining, f, argc = arg->argc - arg->argn;
260040679Sbrian
260140679Sbrian  if (arg->argc == arg->argn) {
260240679Sbrian    arg->bundle->argv[0] = arg->bundle->argv0;
260340679Sbrian    arg->bundle->argv[1] = arg->bundle->argv1;
260440679Sbrian    return 0;
260540679Sbrian  }
260640679Sbrian
260740679Sbrian  if (argc >= sizeof argv / sizeof argv[0]) {
260840679Sbrian    argc = sizeof argv / sizeof argv[0] - 1;
260940679Sbrian    log_Printf(LogWARN, "Truncating proc title to %d args\n", argc);
261040679Sbrian  }
261147849Sbrian  command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 1, getpid());
261240679Sbrian
261340679Sbrian  ptr = title;
261440679Sbrian  remaining = sizeof title - 1;
261540679Sbrian  for (f = 0; f < argc && remaining; f++) {
261640679Sbrian    if (f) {
261740679Sbrian      *ptr++ = ' ';
261840679Sbrian      remaining--;
261940679Sbrian    }
262040679Sbrian    len = strlen(argv[f]);
262140679Sbrian    if (len > remaining)
262240679Sbrian      len = remaining;
262340679Sbrian    memcpy(ptr, argv[f], len);
262440679Sbrian    remaining -= len;
262540679Sbrian    ptr += len;
262640679Sbrian  }
262740679Sbrian  *ptr = '\0';
262840679Sbrian
262940679Sbrian  arg->bundle->argv[0] = title;
263040679Sbrian  arg->bundle->argv[1] = NULL;
263140679Sbrian
263240679Sbrian  return 0;
263340679Sbrian}
2634