command.c revision 53733
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 53733 1999-11-26 22:44:33Z brian $
218857Srgrimes *
226059Samurai */
2343313Sbrian#include <sys/param.h>
2430715Sbrian#include <netinet/in_systm.h>
2526031Sbrian#include <netinet/in.h>
2630715Sbrian#include <netinet/ip.h>
2726031Sbrian#include <arpa/inet.h>
2830715Sbrian#include <sys/socket.h>
2926031Sbrian#include <net/route.h>
3030715Sbrian#include <netdb.h>
3136285Sbrian#include <sys/un.h>
3230715Sbrian
3338628Sbrian#include <ctype.h>
3430715Sbrian#include <errno.h>
3526516Sbrian#include <fcntl.h>
3653298Sbrian#ifdef __OpenBSD__
3753298Sbrian#include <util.h>
3853298Sbrian#else
3953298Sbrian#include <libutil.h>
4053298Sbrian#endif
4130715Sbrian#include <paths.h>
4230715Sbrian#include <stdio.h>
4330715Sbrian#include <stdlib.h>
4430715Sbrian#include <string.h>
4530715Sbrian#include <sys/wait.h>
4630715Sbrian#include <termios.h>
4730715Sbrian#include <unistd.h>
4830715Sbrian
4950059Sbrian#ifndef NONAT
5046086Sbrian#ifdef __FreeBSD__
5146086Sbrian#include <alias.h>
5246086Sbrian#else
5339395Sbrian#include "alias.h"
5439395Sbrian#endif
5539395Sbrian#endif
5646686Sbrian#include "layer.h"
5737009Sbrian#include "defs.h"
5831343Sbrian#include "command.h"
5930715Sbrian#include "mbuf.h"
6030715Sbrian#include "log.h"
6130715Sbrian#include "timer.h"
626059Samurai#include "fsm.h"
636059Samurai#include "lcp.h"
6431690Sbrian#include "iplist.h"
6536285Sbrian#include "throughput.h"
6636285Sbrian#include "slcompress.h"
6738557Sbrian#include "lqr.h"
6838557Sbrian#include "hdlc.h"
696059Samurai#include "ipcp.h"
7050059Sbrian#ifndef NONAT
7151075Sbrian#include "nat_cmd.h"
7231343Sbrian#endif
7325630Sbrian#include "systems.h"
7436285Sbrian#include "filter.h"
7536285Sbrian#include "descriptor.h"
7630715Sbrian#include "main.h"
7730715Sbrian#include "route.h"
7830715Sbrian#include "ccp.h"
7931080Sbrian#include "auth.h"
8036285Sbrian#include "async.h"
8136285Sbrian#include "link.h"
8236285Sbrian#include "physical.h"
8336285Sbrian#include "mp.h"
8443313Sbrian#ifndef NORADIUS
8543313Sbrian#include "radius.h"
8643313Sbrian#endif
8736285Sbrian#include "bundle.h"
8836285Sbrian#include "server.h"
8936285Sbrian#include "prompt.h"
9036285Sbrian#include "chat.h"
9136285Sbrian#include "chap.h"
9238174Sbrian#include "cbcp.h"
9336285Sbrian#include "datalink.h"
9440561Sbrian#include "iface.h"
9553298Sbrian#include "id.h"
966059Samurai
9736285Sbrian/* ``set'' values */
9836285Sbrian#define	VAR_AUTHKEY	0
9936285Sbrian#define	VAR_DIAL	1
10036285Sbrian#define	VAR_LOGIN	2
10136285Sbrian#define	VAR_AUTHNAME	3
10236285Sbrian#define	VAR_AUTOLOAD	4
10336285Sbrian#define	VAR_WINSIZE	5
10436285Sbrian#define	VAR_DEVICE	6
10536285Sbrian#define	VAR_ACCMAP	7
10636285Sbrian#define	VAR_MRRU	8
10736285Sbrian#define	VAR_MRU		9
10836285Sbrian#define	VAR_MTU		10
10936285Sbrian#define	VAR_OPENMODE	11
11036285Sbrian#define	VAR_PHONE	12
11136285Sbrian#define	VAR_HANGUP	13
11236285Sbrian#define	VAR_IDLETIMEOUT	14
11336285Sbrian#define	VAR_LQRPERIOD	15
11436285Sbrian#define	VAR_LCPRETRY	16
11536285Sbrian#define	VAR_CHAPRETRY	17
11636285Sbrian#define	VAR_PAPRETRY	18
11736285Sbrian#define	VAR_CCPRETRY	19
11836285Sbrian#define	VAR_IPCPRETRY	20
11936285Sbrian#define	VAR_DNS		21
12036285Sbrian#define	VAR_NBNS	22
12136285Sbrian#define	VAR_MODE	23
12238174Sbrian#define	VAR_CALLBACK	24
12338174Sbrian#define	VAR_CBCP	25
12438544Sbrian#define	VAR_CHOKED	26
12540665Sbrian#define	VAR_SENDPIPE	27
12640665Sbrian#define	VAR_RECVPIPE	28
12743313Sbrian#define	VAR_RADIUS	29
12844073Sbrian#define	VAR_CD		30
12946686Sbrian#define	VAR_PARITY	31
13046686Sbrian#define VAR_CRTSCTS	32
13150867Sbrian#define VAR_URGENTPORTS	33
13252488Sbrian#define	VAR_LOGOUT	34
1336059Samurai
13436285Sbrian/* ``accept|deny|disable|enable'' masks */
13536285Sbrian#define NEG_HISMASK (1)
13636285Sbrian#define NEG_MYMASK (2)
13736285Sbrian
13836285Sbrian/* ``accept|deny|disable|enable'' values */
13936285Sbrian#define NEG_ACFCOMP	40
14044106Sbrian#define NEG_CHAP05	41
14144106Sbrian#define NEG_CHAP80	42
14244106Sbrian#define NEG_CHAP80LM	43
14344106Sbrian#define NEG_DEFLATE	44
14447858Sbrian#define NEG_DNS		45
14547858Sbrian#define NEG_ENDDISC	46
14647858Sbrian#define NEG_LQR		47
14747858Sbrian#define NEG_PAP		48
14847858Sbrian#define NEG_PPPDDEFLATE	49
14947858Sbrian#define NEG_PRED1	50
15047858Sbrian#define NEG_PROTOCOMP	51
15147858Sbrian#define NEG_SHORTSEQ	52
15247858Sbrian#define NEG_VJCOMP	53
15336285Sbrian
15453684Sbrianconst char Version[] = "2.25";
15536285Sbrian
15636285Sbrianstatic int ShowCommand(struct cmdargs const *);
15736285Sbrianstatic int TerminalCommand(struct cmdargs const *);
15836285Sbrianstatic int QuitCommand(struct cmdargs const *);
15936285Sbrianstatic int OpenCommand(struct cmdargs const *);
16036285Sbrianstatic int CloseCommand(struct cmdargs const *);
16136285Sbrianstatic int DownCommand(struct cmdargs const *);
16236285Sbrianstatic int SetCommand(struct cmdargs const *);
16336285Sbrianstatic int LinkCommand(struct cmdargs const *);
16436285Sbrianstatic int AddCommand(struct cmdargs const *);
16536285Sbrianstatic int DeleteCommand(struct cmdargs const *);
16636285Sbrianstatic int NegotiateCommand(struct cmdargs const *);
16736934Sbrianstatic int ClearCommand(struct cmdargs const *);
16840561Sbrianstatic int RunListCommand(struct cmdargs const *);
16940561Sbrianstatic int IfaceAddCommand(struct cmdargs const *);
17040561Sbrianstatic int IfaceDeleteCommand(struct cmdargs const *);
17140561Sbrianstatic int IfaceClearCommand(struct cmdargs const *);
17240679Sbrianstatic int SetProcTitle(struct cmdargs const *);
17350059Sbrian#ifndef NONAT
17436285Sbrianstatic int AliasEnable(struct cmdargs const *);
17536285Sbrianstatic int AliasOption(struct cmdargs const *);
17631343Sbrian#endif
1776059Samurai
17836285Sbrianstatic const char *
17936285Sbrianshowcx(struct cmdtab const *cmd)
18036285Sbrian{
18136285Sbrian  if (cmd->lauth & LOCAL_CX)
18236285Sbrian    return "(c)";
18336285Sbrian  else if (cmd->lauth & LOCAL_CX_OPT)
18436285Sbrian    return "(o)";
18536285Sbrian
18636285Sbrian  return "";
18736285Sbrian}
18836285Sbrian
1896059Samuraistatic int
19031343SbrianHelpCommand(struct cmdargs const *arg)
1916059Samurai{
19228679Sbrian  struct cmdtab const *cmd;
19336285Sbrian  int n, cmax, dmax, cols, cxlen;
19436285Sbrian  const char *cx;
1956059Samurai
19636285Sbrian  if (!arg->prompt) {
19736285Sbrian    log_Printf(LogWARN, "help: Cannot help without a prompt\n");
19826516Sbrian    return 0;
19936285Sbrian  }
20026516Sbrian
20136285Sbrian  if (arg->argc > arg->argn) {
20236285Sbrian    for (cmd = arg->cmdtab; cmd->name || cmd->alias; cmd++)
20336285Sbrian      if ((cmd->lauth & arg->prompt->auth) &&
20436285Sbrian          ((cmd->name && !strcasecmp(cmd->name, arg->argv[arg->argn])) ||
20536285Sbrian           (cmd->alias && !strcasecmp(cmd->alias, arg->argv[arg->argn])))) {
20636285Sbrian	prompt_Printf(arg->prompt, "%s %s\n", cmd->syntax, showcx(cmd));
20728679Sbrian	return 0;
2086059Samurai      }
20926516Sbrian    return -1;
2106059Samurai  }
21136285Sbrian
21231372Sbrian  cmax = dmax = 0;
21336285Sbrian  for (cmd = arg->cmdtab; cmd->func; cmd++)
21436285Sbrian    if (cmd->name && (cmd->lauth & arg->prompt->auth)) {
21536285Sbrian      if ((n = strlen(cmd->name) + strlen(showcx(cmd))) > cmax)
21631372Sbrian        cmax = n;
21731372Sbrian      if ((n = strlen(cmd->helpmes)) > dmax)
21831372Sbrian        dmax = n;
21931372Sbrian    }
22031372Sbrian
22131372Sbrian  cols = 80 / (dmax + cmax + 3);
2226059Samurai  n = 0;
22336285Sbrian  prompt_Printf(arg->prompt, "(o) = Optional context,"
22436285Sbrian                " (c) = Context required\n");
22536285Sbrian  for (cmd = arg->cmdtab; cmd->func; cmd++)
22636285Sbrian    if (cmd->name && (cmd->lauth & arg->prompt->auth)) {
22736285Sbrian      cx = showcx(cmd);
22836285Sbrian      cxlen = cmax - strlen(cmd->name);
22940482Sbrian      if (n % cols != 0)
23040482Sbrian        prompt_Printf(arg->prompt, " ");
23140482Sbrian      prompt_Printf(arg->prompt, "%s%-*.*s: %-*.*s",
23236285Sbrian              cmd->name, cxlen, cxlen, cx, dmax, dmax, cmd->helpmes);
23331372Sbrian      if (++n % cols == 0)
23436285Sbrian        prompt_Printf(arg->prompt, "\n");
2356059Samurai    }
23631372Sbrian  if (n % cols != 0)
23736285Sbrian    prompt_Printf(arg->prompt, "\n");
23826516Sbrian
23926516Sbrian  return 0;
2406059Samurai}
2416059Samurai
24236285Sbrianstatic int
24336285SbrianCloneCommand(struct cmdargs const *arg)
2446059Samurai{
24536285Sbrian  char namelist[LINE_LEN];
24636285Sbrian  char *name;
24736285Sbrian  int f;
2486059Samurai
24936285Sbrian  if (arg->argc == arg->argn)
25036285Sbrian    return -1;
25136285Sbrian
25236285Sbrian  namelist[sizeof namelist - 1] = '\0';
25336285Sbrian  for (f = arg->argn; f < arg->argc; f++) {
25436285Sbrian    strncpy(namelist, arg->argv[f], sizeof namelist - 1);
25536285Sbrian    for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
25636285Sbrian      bundle_DatalinkClone(arg->bundle, arg->cx, name);
2576059Samurai  }
25836285Sbrian
25936285Sbrian  return 0;
2606059Samurai}
2616059Samurai
2626059Samuraistatic int
26336285SbrianRemoveCommand(struct cmdargs const *arg)
2646059Samurai{
26536285Sbrian  if (arg->argc != arg->argn)
26636285Sbrian    return -1;
26711336Samurai
26836285Sbrian  if (arg->cx->state != DATALINK_CLOSED) {
26936285Sbrian    log_Printf(LogWARN, "remove: Cannot delete links that aren't closed\n");
27036285Sbrian    return 2;
2716059Samurai  }
27226516Sbrian
27336285Sbrian  bundle_DatalinkRemove(arg->bundle, arg->cx);
27436285Sbrian  return 0;
27536285Sbrian}
27632711Sbrian
27736285Sbrianstatic int
27836285SbrianRenameCommand(struct cmdargs const *arg)
27936285Sbrian{
28036285Sbrian  if (arg->argc != arg->argn + 1)
28136285Sbrian    return -1;
28231121Sbrian
28336285Sbrian  if (bundle_RenameDatalink(arg->bundle, arg->cx, arg->argv[arg->argn]))
28436285Sbrian    return 0;
28536285Sbrian
28636285Sbrian  log_Printf(LogWARN, "%s -> %s: target name already exists\n",
28736285Sbrian             arg->cx->name, arg->argv[arg->argn]);
28836285Sbrian  return 1;
28936285Sbrian}
29036285Sbrian
29136285Sbrianint
29236285SbrianLoadCommand(struct cmdargs const *arg)
29336285Sbrian{
29440797Sbrian  const char *err;
29540797Sbrian  int n, mode;
29636285Sbrian
29740797Sbrian  mode = arg->bundle->phys_type.all;
29836285Sbrian
29940797Sbrian  if (arg->argn < arg->argc) {
30040797Sbrian    for (n = arg->argn; n < arg->argc; n++)
30140797Sbrian      if ((err = system_IsValid(arg->argv[n], arg->prompt, mode)) != NULL) {
30240797Sbrian        log_Printf(LogWARN, "%s: %s\n", arg->argv[n], err);
30340797Sbrian        return 1;
30440797Sbrian      }
30540797Sbrian
30640797Sbrian    for (n = arg->argn; n < arg->argc; n++) {
30740797Sbrian      bundle_SetLabel(arg->bundle, arg->argv[arg->argc - 1]);
30840797Sbrian      system_Select(arg->bundle, arg->argv[n], CONFFILE, arg->prompt, arg->cx);
30940797Sbrian    }
31040797Sbrian    bundle_SetLabel(arg->bundle, arg->argv[arg->argc - 1]);
31140797Sbrian  } else if ((err = system_IsValid("default", arg->prompt, mode)) != NULL) {
31240797Sbrian    log_Printf(LogWARN, "default: %s\n", err);
31336285Sbrian    return 1;
31436285Sbrian  } else {
31540797Sbrian    bundle_SetLabel(arg->bundle, "default");
31640797Sbrian    system_Select(arg->bundle, "default", CONFFILE, arg->prompt, arg->cx);
31740797Sbrian    bundle_SetLabel(arg->bundle, "default");
31836285Sbrian  }
31940797Sbrian
32026516Sbrian  return 0;
3216059Samurai}
3226059Samurai
32336285Sbrianint
32436285SbrianSaveCommand(struct cmdargs const *arg)
32536285Sbrian{
32636285Sbrian  log_Printf(LogWARN, "save command is not implemented (yet).\n");
32736285Sbrian  return 1;
32836285Sbrian}
32936285Sbrian
33010528Samuraistatic int
33136285SbrianDialCommand(struct cmdargs const *arg)
33228536Sbrian{
33336285Sbrian  int res;
33436285Sbrian
33536465Sbrian  if ((arg->cx && !(arg->cx->physical->type & (PHYS_INTERACTIVE|PHYS_AUTO)))
33636465Sbrian      || (!arg->cx &&
33736928Sbrian          (arg->bundle->phys_type.all & ~(PHYS_INTERACTIVE|PHYS_AUTO)))) {
33836285Sbrian    log_Printf(LogWARN, "Manual dial is only available for auto and"
33936285Sbrian              " interactive links\n");
34036285Sbrian    return 1;
34134536Sbrian  }
34236285Sbrian
34336285Sbrian  if (arg->argc > arg->argn && (res = LoadCommand(arg)) != 0)
34436285Sbrian    return res;
34536285Sbrian
34637993Sbrian  bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1);
34736285Sbrian
34836285Sbrian  return 0;
34928536Sbrian}
35028536Sbrian
35138628Sbrian#define isinword(ch) (isalnum(ch) || (ch) == '_')
35238628Sbrian
35338628Sbrianstatic char *
35438628Sbrianstrstrword(char *big, const char *little)
35538628Sbrian{
35638628Sbrian  /* Get the first occurance of the word ``little'' in ``big'' */
35738628Sbrian  char *pos;
35838628Sbrian  int len;
35938628Sbrian
36038628Sbrian  pos = big;
36138628Sbrian  len = strlen(little);
36238628Sbrian
36338628Sbrian  while ((pos = strstr(pos, little)) != NULL)
36447865Sbrian    if ((pos != big && isinword(pos[-1])) || isinword(pos[len]))
36547865Sbrian      pos++;
36647865Sbrian    else if (pos != big && pos[-1] == '\\')
36747865Sbrian      memmove(pos - 1, pos, strlen(pos) + 1);
36847865Sbrian    else
36938628Sbrian      break;
37038628Sbrian
37138628Sbrian  return pos;
37238628Sbrian}
37338628Sbrian
37438628Sbrianstatic char *
37538628Sbriansubst(char *tgt, const char *oldstr, const char *newstr)
37638628Sbrian{
37738628Sbrian  /* tgt is a malloc()d area... realloc() as necessary */
37838628Sbrian  char *word, *ntgt;
37938628Sbrian  int ltgt, loldstr, lnewstr, pos;
38038628Sbrian
38138628Sbrian  if ((word = strstrword(tgt, oldstr)) == NULL)
38238628Sbrian    return tgt;
38338628Sbrian
38438628Sbrian  ltgt = strlen(tgt) + 1;
38538628Sbrian  loldstr = strlen(oldstr);
38638628Sbrian  lnewstr = strlen(newstr);
38738628Sbrian  do {
38838628Sbrian    pos = word - tgt;
38938628Sbrian    if (loldstr > lnewstr)
39038628Sbrian      bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr);
39138628Sbrian    if (loldstr != lnewstr) {
39238628Sbrian      ntgt = realloc(tgt, ltgt += lnewstr - loldstr);
39338628Sbrian      if (ntgt == NULL)
39438628Sbrian        break;			/* Oh wonderful ! */
39538628Sbrian      word = ntgt + pos;
39638628Sbrian      tgt = ntgt;
39738628Sbrian    }
39838628Sbrian    if (lnewstr > loldstr)
39938628Sbrian      bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr);
40038628Sbrian    bcopy(newstr, word, lnewstr);
40138628Sbrian  } while ((word = strstrword(word, oldstr)));
40238628Sbrian
40338628Sbrian  return tgt;
40438628Sbrian}
40538628Sbrian
40643888Sbrianvoid
40743888Sbriancommand_Expand(char **nargv, int argc, char const *const *oargv,
40847849Sbrian               struct bundle *bundle, int inc0, pid_t pid)
40938628Sbrian{
41038628Sbrian  int arg;
41147849Sbrian  char pidstr[12];
41238628Sbrian
41341755Sbrian  if (inc0)
41441755Sbrian    arg = 0;		/* Start at arg 0 */
41541755Sbrian  else {
41641755Sbrian    nargv[0] = strdup(oargv[0]);
41741755Sbrian    arg = 1;
41841755Sbrian  }
41947849Sbrian  snprintf(pidstr, sizeof pidstr, "%d", (int)pid);
42041755Sbrian  for (; arg < argc; arg++) {
42138629Sbrian    nargv[arg] = strdup(oargv[arg]);
42238629Sbrian    nargv[arg] = subst(nargv[arg], "HISADDR",
42338628Sbrian                       inet_ntoa(bundle->ncp.ipcp.peer_ip));
42438629Sbrian    nargv[arg] = subst(nargv[arg], "AUTHNAME", bundle->cfg.auth.name);
42540561Sbrian    nargv[arg] = subst(nargv[arg], "INTERFACE", bundle->iface->name);
42638628Sbrian    nargv[arg] = subst(nargv[arg], "MYADDR", inet_ntoa(bundle->ncp.ipcp.my_ip));
42738629Sbrian    nargv[arg] = subst(nargv[arg], "USER", bundle->ncp.mp.peer.authname);
42838629Sbrian    nargv[arg] = subst(nargv[arg], "PEER_ENDDISC",
42938629Sbrian                       mp_Enddisc(bundle->ncp.mp.peer.enddisc.class,
43038629Sbrian                                  bundle->ncp.mp.peer.enddisc.address,
43138629Sbrian                                  bundle->ncp.mp.peer.enddisc.len));
43238629Sbrian    nargv[arg] = subst(nargv[arg], "ENDDISC",
43338629Sbrian                       mp_Enddisc(bundle->ncp.mp.cfg.enddisc.class,
43438629Sbrian                                  bundle->ncp.mp.cfg.enddisc.address,
43538629Sbrian                                  bundle->ncp.mp.cfg.enddisc.len));
43647849Sbrian    nargv[arg] = subst(nargv[arg], "PROCESSID", pidstr);
43738629Sbrian    nargv[arg] = subst(nargv[arg], "LABEL", bundle_GetLabel(bundle));
43838628Sbrian  }
43938628Sbrian  nargv[arg] = NULL;
44038628Sbrian}
44138628Sbrian
44228536Sbrianstatic int
44331343SbrianShellCommand(struct cmdargs const *arg, int bg)
44410528Samurai{
44510528Samurai  const char *shell;
44647849Sbrian  pid_t shpid, pid;
44720813Sjkh
44818856Ssos#ifdef SHELL_ONLY_INTERACTIVELY
44926911Sbrian  /* we're only allowed to shell when we run ppp interactively */
45036285Sbrian  if (arg->prompt && arg->prompt->owner) {
45136285Sbrian    log_Printf(LogWARN, "Can't start a shell from a network connection\n");
45226516Sbrian    return 1;
45310528Samurai  }
45426911Sbrian#endif
45528679Sbrian
45636285Sbrian  if (arg->argc == arg->argn) {
45736285Sbrian    if (!arg->prompt) {
45836285Sbrian      log_Printf(LogWARN, "Can't start an interactive shell from"
45936285Sbrian                " a config file\n");
46028381Sbrian      return 1;
46136285Sbrian    } else if (arg->prompt->owner) {
46236285Sbrian      log_Printf(LogWARN, "Can't start an interactive shell from"
46336285Sbrian                " a socket connection\n");
46436285Sbrian      return 1;
46528381Sbrian    } else if (bg) {
46636285Sbrian      log_Printf(LogWARN, "Can only start an interactive shell in"
46728679Sbrian		" the foreground mode\n");
46828381Sbrian      return 1;
46928381Sbrian    }
47034536Sbrian  }
47134536Sbrian
47247849Sbrian  pid = getpid();
47328679Sbrian  if ((shpid = fork()) == 0) {
47436285Sbrian    int i, fd;
47518531Sbde
47636285Sbrian    if ((shell = getenv("SHELL")) == 0)
47736285Sbrian      shell = _PATH_BSHELL;
47832017Sbrian
47936285Sbrian    timer_TermService();
48036285Sbrian
48136285Sbrian    if (arg->prompt)
48236285Sbrian      fd = arg->prompt->fd_out;
48336285Sbrian    else if ((fd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
48436285Sbrian      log_Printf(LogALERT, "Failed to open %s: %s\n",
48536285Sbrian                _PATH_DEVNULL, strerror(errno));
48628679Sbrian      exit(1);
48728679Sbrian    }
48849976Sbrian    dup2(fd, STDIN_FILENO);
48949976Sbrian    dup2(fd, STDOUT_FILENO);
49049976Sbrian    dup2(fd, STDERR_FILENO);
49149976Sbrian    for (i = getdtablesize(); i > STDERR_FILENO; i--)
49249976Sbrian      fcntl(i, F_SETFD, 1);
49326516Sbrian
49431061Sbrian    setuid(geteuid());
49536285Sbrian    if (arg->argc > arg->argn) {
49628679Sbrian      /* substitute pseudo args */
49738628Sbrian      char *argv[MAXARGS];
49838628Sbrian      int argc = arg->argc - arg->argn;
49938628Sbrian
50038628Sbrian      if (argc >= sizeof argv / sizeof argv[0]) {
50138628Sbrian        argc = sizeof argv / sizeof argv[0] - 1;
50238628Sbrian        log_Printf(LogWARN, "Truncating shell command to %d args\n", argc);
50331343Sbrian      }
50447849Sbrian      command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 0, pid);
50528679Sbrian      if (bg) {
50628679Sbrian	pid_t p;
50710528Samurai
50828679Sbrian	p = getpid();
50928679Sbrian	if (daemon(1, 1) == -1) {
51036832Sbrian	  log_Printf(LogERROR, "%d: daemon: %s\n", (int)p, strerror(errno));
51128679Sbrian	  exit(1);
51228679Sbrian	}
51336285Sbrian      } else if (arg->prompt)
51436285Sbrian        printf("ppp: Pausing until %s finishes\n", arg->argv[arg->argn]);
51531343Sbrian      execvp(argv[0], argv);
51630316Sbrian    } else {
51736285Sbrian      if (arg->prompt)
51832017Sbrian        printf("ppp: Pausing until %s finishes\n", shell);
51936285Sbrian      prompt_TtyOldMode(arg->prompt);
52031343Sbrian      execl(shell, shell, NULL);
52130316Sbrian    }
52220813Sjkh
52340665Sbrian    log_Printf(LogWARN, "exec() of %s failed: %s\n",
52440665Sbrian              arg->argc > arg->argn ? arg->argv[arg->argn] : shell,
52540665Sbrian              strerror(errno));
52649976Sbrian    _exit(255);
52710528Samurai  }
52836285Sbrian
52936285Sbrian  if (shpid == (pid_t) - 1)
53036285Sbrian    log_Printf(LogERROR, "Fork failed: %s\n", strerror(errno));
53136285Sbrian  else {
53210528Samurai    int status;
53331343Sbrian    waitpid(shpid, &status, 0);
53410528Samurai  }
53520813Sjkh
53636285Sbrian  if (arg->prompt && !arg->prompt->owner)
53736285Sbrian    prompt_TtyCommandMode(arg->prompt);
53820813Sjkh
53936285Sbrian  return 0;
54010528Samurai}
54110528Samurai
54231343Sbrianstatic int
54331343SbrianBgShellCommand(struct cmdargs const *arg)
54431343Sbrian{
54536285Sbrian  if (arg->argc == arg->argn)
54631343Sbrian    return -1;
54731343Sbrian  return ShellCommand(arg, 1);
54831343Sbrian}
54931343Sbrian
55031343Sbrianstatic int
55131343SbrianFgShellCommand(struct cmdargs const *arg)
55231343Sbrian{
55331343Sbrian  return ShellCommand(arg, 0);
55431343Sbrian}
55531343Sbrian
55650059Sbrian#ifndef NONAT
55740561Sbrianstatic struct cmdtab const AliasCommands[] =
55840561Sbrian{
55950059Sbrian  {"addr", NULL, nat_RedirectAddr, LOCAL_AUTH,
56050059Sbrian   "static address translation", "nat addr [addr_local addr_alias]"},
56140561Sbrian  {"deny_incoming", NULL, AliasOption, LOCAL_AUTH,
56250059Sbrian   "stop incoming connections", "nat deny_incoming yes|no",
56340561Sbrian   (const void *) PKT_ALIAS_DENY_INCOMING},
56440561Sbrian  {"enable", NULL, AliasEnable, LOCAL_AUTH,
56550059Sbrian   "enable NAT", "nat enable yes|no"},
56640561Sbrian  {"log", NULL, AliasOption, LOCAL_AUTH,
56750059Sbrian   "log NAT link creation", "nat log yes|no",
56840561Sbrian   (const void *) PKT_ALIAS_LOG},
56950059Sbrian  {"port", NULL, nat_RedirectPort, LOCAL_AUTH, "port redirection",
57050059Sbrian   "nat port proto localaddr:port[-port] aliasport[-aliasport]"},
57150059Sbrian  {"pptp", NULL, nat_Pptp, LOCAL_AUTH,
57250059Sbrian   "Set the PPTP address", "nat pptp IP"},
57350059Sbrian  {"proxy", NULL, nat_ProxyRule, LOCAL_AUTH,
57450059Sbrian   "proxy control", "nat proxy server host[:port] ..."},
57540561Sbrian  {"same_ports", NULL, AliasOption, LOCAL_AUTH,
57650059Sbrian   "try to leave port numbers unchanged", "nat same_ports yes|no",
57740561Sbrian   (const void *) PKT_ALIAS_SAME_PORTS},
57840561Sbrian  {"unregistered_only", NULL, AliasOption, LOCAL_AUTH,
57950059Sbrian   "translate unregistered (private) IP address space only",
58050059Sbrian   "nat unregistered_only yes|no",
58140561Sbrian   (const void *) PKT_ALIAS_UNREGISTERED_ONLY},
58240561Sbrian  {"use_sockets", NULL, AliasOption, LOCAL_AUTH,
58350059Sbrian   "allocate host sockets", "nat use_sockets yes|no",
58440561Sbrian   (const void *) PKT_ALIAS_USE_SOCKETS},
58540561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
58650059Sbrian   "Display this message", "nat help|? [command]", AliasCommands},
58740561Sbrian  {NULL, NULL, NULL},
58840561Sbrian};
58940561Sbrian#endif
59040561Sbrian
59140561Sbrianstatic struct cmdtab const AllowCommands[] = {
59240561Sbrian  {"modes", "mode", AllowModes, LOCAL_AUTH,
59340561Sbrian  "Only allow certain ppp modes", "allow modes mode..."},
59440561Sbrian  {"users", "user", AllowUsers, LOCAL_AUTH,
59540561Sbrian  "Only allow ppp access to certain users", "allow users logname..."},
59640561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
59740561Sbrian  "Display this message", "allow help|? [command]", AllowCommands},
59840561Sbrian  {NULL, NULL, NULL},
59940561Sbrian};
60040561Sbrian
60140561Sbrianstatic struct cmdtab const IfaceCommands[] =
60240561Sbrian{
60340561Sbrian  {"add", NULL, IfaceAddCommand, LOCAL_AUTH,
60440561Sbrian   "Add iface address", "iface add addr[/bits| mask] peer", NULL},
60540561Sbrian  {NULL, "add!", IfaceAddCommand, LOCAL_AUTH,
60640561Sbrian   "Add or change an iface address", "iface add! addr[/bits| mask] peer",
60740561Sbrian   (void *)1},
60840561Sbrian  {"clear", NULL, IfaceClearCommand, LOCAL_AUTH,
60940561Sbrian   "Clear iface address(es)", "iface clear"},
61040561Sbrian  {"delete", "rm", IfaceDeleteCommand, LOCAL_AUTH,
61140561Sbrian   "Delete iface address", "iface delete addr", NULL},
61240561Sbrian  {NULL, "rm!", IfaceDeleteCommand, LOCAL_AUTH,
61340561Sbrian   "Delete iface address", "iface delete addr", (void *)1},
61440561Sbrian  {NULL, "delete!", IfaceDeleteCommand, LOCAL_AUTH,
61540561Sbrian   "Delete iface address", "iface delete addr", (void *)1},
61640561Sbrian  {"show", NULL, iface_Show, LOCAL_AUTH,
61740561Sbrian   "Show iface address(es)", "iface show"},
61840561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
61950059Sbrian   "Display this message", "nat help|? [command]", IfaceCommands},
62040561Sbrian  {NULL, NULL, NULL},
62140561Sbrian};
62240561Sbrian
62330715Sbrianstatic struct cmdtab const Commands[] = {
62436285Sbrian  {"accept", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
62528679Sbrian  "accept option request", "accept option .."},
62628679Sbrian  {"add", NULL, AddCommand, LOCAL_AUTH,
62732109Sbrian  "add route", "add dest mask gateway", NULL},
62836285Sbrian  {NULL, "add!", AddCommand, LOCAL_AUTH,
62932109Sbrian  "add or change route", "add! dest mask gateway", (void *)1},
63040561Sbrian  {"allow", "auth", RunListCommand, LOCAL_AUTH,
63140561Sbrian  "Allow ppp access", "allow users|modes ....", AllowCommands},
63228679Sbrian  {"bg", "!bg", BgShellCommand, LOCAL_AUTH,
63331372Sbrian  "Run a background command", "[!]bg command"},
63436934Sbrian  {"clear", NULL, ClearCommand, LOCAL_AUTH | LOCAL_CX_OPT,
63546686Sbrian  "Clear throughput statistics",
63646686Sbrian  "clear ipcp|physical [current|overall|peak]..."},
63736285Sbrian  {"clone", NULL, CloneCommand, LOCAL_AUTH | LOCAL_CX,
63836285Sbrian  "Clone a link", "clone newname..."},
63936285Sbrian  {"close", NULL, CloseCommand, LOCAL_AUTH | LOCAL_CX_OPT,
64036285Sbrian  "Close an FSM", "close [lcp|ccp]"},
64128679Sbrian  {"delete", NULL, DeleteCommand, LOCAL_AUTH,
64232109Sbrian  "delete route", "delete dest", NULL},
64336285Sbrian  {NULL, "delete!", DeleteCommand, LOCAL_AUTH,
64432109Sbrian  "delete a route if it exists", "delete! dest", (void *)1},
64536285Sbrian  {"deny", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
64628679Sbrian  "Deny option request", "deny option .."},
64736285Sbrian  {"dial", "call", DialCommand, LOCAL_AUTH | LOCAL_CX_OPT,
64840797Sbrian  "Dial and login", "dial|call [system ...]", NULL},
64936285Sbrian  {"disable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
65028679Sbrian  "Disable option", "disable option .."},
65136285Sbrian  {"down", NULL, DownCommand, LOCAL_AUTH | LOCAL_CX_OPT,
65246686Sbrian  "Generate a down event", "down [ccp|lcp]"},
65336285Sbrian  {"enable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
65428679Sbrian  "Enable option", "enable option .."},
65540561Sbrian  {"iface", "interface", RunListCommand, LOCAL_AUTH,
65640561Sbrian  "interface control", "iface option ...", IfaceCommands},
65736285Sbrian  {"link", "datalink", LinkCommand, LOCAL_AUTH,
65836285Sbrian  "Link specific commands", "link name command ..."},
65937008Sbrian  {"load", NULL, LoadCommand, LOCAL_AUTH | LOCAL_CX_OPT,
66040797Sbrian  "Load settings", "load [system ...]"},
66150059Sbrian#ifndef NONAT
66250059Sbrian  {"nat", "alias", RunListCommand, LOCAL_AUTH,
66350059Sbrian  "NAT control", "nat option yes|no", AliasCommands},
66450059Sbrian#endif
66536285Sbrian  {"open", NULL, OpenCommand, LOCAL_AUTH | LOCAL_CX_OPT,
66637955Sbrian  "Open an FSM", "open! [lcp|ccp|ipcp]", (void *)1},
66736285Sbrian  {"passwd", NULL, PasswdCommand, LOCAL_NO_AUTH,
66836285Sbrian  "Password for manipulation", "passwd LocalPassword"},
66936285Sbrian  {"quit", "bye", QuitCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
67036285Sbrian  "Quit PPP program", "quit|bye [all]"},
67136285Sbrian  {"remove", "rm", RemoveCommand, LOCAL_AUTH | LOCAL_CX,
67236285Sbrian  "Remove a link", "remove"},
67336285Sbrian  {"rename", "mv", RenameCommand, LOCAL_AUTH | LOCAL_CX,
67436285Sbrian  "Rename a link", "rename name"},
67528679Sbrian  {"save", NULL, SaveCommand, LOCAL_AUTH,
67628679Sbrian  "Save settings", "save"},
67736285Sbrian  {"set", "setup", SetCommand, LOCAL_AUTH | LOCAL_CX_OPT,
67828679Sbrian  "Set parameters", "set[up] var value"},
67928679Sbrian  {"shell", "!", FgShellCommand, LOCAL_AUTH,
68028679Sbrian  "Run a subshell", "shell|! [sh command]"},
68136285Sbrian  {"show", NULL, ShowCommand, LOCAL_AUTH | LOCAL_CX_OPT,
68231372Sbrian  "Show status and stats", "show var"},
68336285Sbrian  {"term", NULL, TerminalCommand, LOCAL_AUTH | LOCAL_CX,
68431372Sbrian  "Enter terminal mode", "term"},
68528679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
68631343Sbrian  "Display this message", "help|? [command]", Commands},
68728679Sbrian  {NULL, NULL, NULL},
6886059Samurai};
6896059Samurai
69028536Sbrianstatic int
69131343SbrianShowEscape(struct cmdargs const *arg)
6926059Samurai{
69336285Sbrian  if (arg->cx->physical->async.cfg.EscMap[32]) {
69436285Sbrian    int code, bit;
69536285Sbrian    const char *sep = "";
6966059Samurai
69726516Sbrian    for (code = 0; code < 32; code++)
69836285Sbrian      if (arg->cx->physical->async.cfg.EscMap[code])
69928679Sbrian	for (bit = 0; bit < 8; bit++)
70036285Sbrian	  if (arg->cx->physical->async.cfg.EscMap[code] & (1 << bit)) {
70136285Sbrian	    prompt_Printf(arg->prompt, "%s0x%02x", sep, (code << 3) + bit);
70236285Sbrian            sep = ", ";
70336285Sbrian          }
70436285Sbrian    prompt_Printf(arg->prompt, "\n");
7056059Samurai  }
70631077Sbrian  return 0;
7076059Samurai}
7086059Samurai
70928679Sbrianstatic int
71036285SbrianShowTimerList(struct cmdargs const *arg)
7116059Samurai{
71236285Sbrian  timer_Show(0, arg->prompt);
71331077Sbrian  return 0;
7146059Samurai}
7156059Samurai
71628679Sbrianstatic int
71731343SbrianShowStopped(struct cmdargs const *arg)
71828327Sbrian{
71936285Sbrian  prompt_Printf(arg->prompt, " Stopped Timer:  LCP: ");
72036285Sbrian  if (!arg->cx->physical->link.lcp.fsm.StoppedTimer.load)
72136285Sbrian    prompt_Printf(arg->prompt, "Disabled");
72228327Sbrian  else
72336285Sbrian    prompt_Printf(arg->prompt, "%ld secs",
72436285Sbrian                  arg->cx->physical->link.lcp.fsm.StoppedTimer.load / SECTICKS);
72528461Sbrian
72636285Sbrian  prompt_Printf(arg->prompt, ", CCP: ");
72736285Sbrian  if (!arg->cx->physical->link.ccp.fsm.StoppedTimer.load)
72836285Sbrian    prompt_Printf(arg->prompt, "Disabled");
72928461Sbrian  else
73036285Sbrian    prompt_Printf(arg->prompt, "%ld secs",
73136285Sbrian                  arg->cx->physical->link.ccp.fsm.StoppedTimer.load / SECTICKS);
73228461Sbrian
73336285Sbrian  prompt_Printf(arg->prompt, "\n");
73428461Sbrian
73531077Sbrian  return 0;
73628327Sbrian}
73728327Sbrian
73828679Sbrianstatic int
73931343SbrianShowVersion(struct cmdargs const *arg)
7406059Samurai{
74151026Sbrian  prompt_Printf(arg->prompt, "PPP Version %s - %s\n", Version, __DATE__);
74231077Sbrian  return 0;
7436059Samurai}
7446059Samurai
74528679Sbrianstatic int
74636285SbrianShowProtocolStats(struct cmdargs const *arg)
74726326Sbrian{
74836285Sbrian  struct link *l = command_ChooseLink(arg);
74926326Sbrian
75036285Sbrian  prompt_Printf(arg->prompt, "%s:\n", l->name);
75136285Sbrian  link_ReportProtocolStatus(l, arg->prompt);
75231077Sbrian  return 0;
75326326Sbrian}
75426326Sbrian
75530715Sbrianstatic struct cmdtab const ShowCommands[] = {
75636285Sbrian  {"bundle", NULL, bundle_ShowStatus, LOCAL_AUTH,
75736285Sbrian  "bundle details", "show bundle"},
75836285Sbrian  {"ccp", NULL, ccp_ReportStatus, LOCAL_AUTH | LOCAL_CX_OPT,
75936285Sbrian  "CCP status", "show cpp"},
76036285Sbrian  {"compress", NULL, sl_Show, LOCAL_AUTH,
76136285Sbrian  "VJ compression stats", "show compress"},
76236285Sbrian  {"escape", NULL, ShowEscape, LOCAL_AUTH | LOCAL_CX,
76336285Sbrian  "escape characters", "show escape"},
76436285Sbrian  {"filter", NULL, filter_Show, LOCAL_AUTH,
76536285Sbrian  "packet filters", "show filter [in|out|dial|alive]"},
76636285Sbrian  {"hdlc", NULL, hdlc_ReportStatus, LOCAL_AUTH | LOCAL_CX,
76736285Sbrian  "HDLC errors", "show hdlc"},
76840561Sbrian  {"iface", "interface", iface_Show, LOCAL_AUTH,
76940561Sbrian  "Interface status", "show iface"},
77036285Sbrian  {"ipcp", NULL, ipcp_Show, LOCAL_AUTH,
77136285Sbrian  "IPCP status", "show ipcp"},
77247211Sbrian  {"layers", NULL, link_ShowLayers, LOCAL_AUTH | LOCAL_CX_OPT,
77347211Sbrian  "Protocol layers", "show layers"},
77436285Sbrian  {"lcp", NULL, lcp_ReportStatus, LOCAL_AUTH | LOCAL_CX,
77536285Sbrian  "LCP status", "show lcp"},
77636285Sbrian  {"link", "datalink", datalink_Show, LOCAL_AUTH | LOCAL_CX,
77736285Sbrian  "(high-level) link info", "show link"},
77836285Sbrian  {"links", NULL, bundle_ShowLinks, LOCAL_AUTH,
77936285Sbrian  "available link names", "show links"},
78036285Sbrian  {"log", NULL, log_ShowLevel, LOCAL_AUTH,
78136285Sbrian  "log levels", "show log"},
78236285Sbrian  {"mem", NULL, mbuf_Show, LOCAL_AUTH,
78336285Sbrian  "mbuf allocations", "show mem"},
78446686Sbrian  {"physical", NULL, physical_ShowStatus, LOCAL_AUTH | LOCAL_CX,
78546686Sbrian  "(low-level) link info", "show physical"},
78636285Sbrian  {"mp", "multilink", mp_ShowStatus, LOCAL_AUTH,
78736285Sbrian  "multilink setup", "show mp"},
78836285Sbrian  {"proto", NULL, ShowProtocolStats, LOCAL_AUTH | LOCAL_CX_OPT,
78936285Sbrian  "protocol summary", "show proto"},
79036285Sbrian  {"route", NULL, route_Show, LOCAL_AUTH,
79136285Sbrian  "routing table", "show route"},
79236285Sbrian  {"stopped", NULL, ShowStopped, LOCAL_AUTH | LOCAL_CX,
79336285Sbrian  "STOPPED timeout", "show stopped"},
79436285Sbrian  {"timers", NULL, ShowTimerList, LOCAL_AUTH,
79536285Sbrian  "alarm timers", "show timers"},
79628679Sbrian  {"version", NULL, ShowVersion, LOCAL_NO_AUTH | LOCAL_AUTH,
79736285Sbrian  "version string", "show version"},
79836285Sbrian  {"who", NULL, log_ShowWho, LOCAL_AUTH,
79936285Sbrian  "client list", "show who"},
80028679Sbrian  {"help", "?", HelpCommand, LOCAL_NO_AUTH | LOCAL_AUTH,
80131343Sbrian  "Display this message", "show help|? [command]", ShowCommands},
80228679Sbrian  {NULL, NULL, NULL},
8036059Samurai};
8046059Samurai
80530715Sbrianstatic struct cmdtab const *
80631343SbrianFindCommand(struct cmdtab const *cmds, const char *str, int *pmatch)
8076059Samurai{
80826516Sbrian  int nmatch;
80926516Sbrian  int len;
81028679Sbrian  struct cmdtab const *found;
8116059Samurai
81226516Sbrian  found = NULL;
81326516Sbrian  len = strlen(str);
81426516Sbrian  nmatch = 0;
8156059Samurai  while (cmds->func) {
81625566Sbrian    if (cmds->name && strncasecmp(str, cmds->name, len) == 0) {
81726516Sbrian      if (cmds->name[len] == '\0') {
81828679Sbrian	*pmatch = 1;
81928679Sbrian	return cmds;
82026516Sbrian      }
8216059Samurai      nmatch++;
8226059Samurai      found = cmds;
82328679Sbrian    } else if (cmds->alias && strncasecmp(str, cmds->alias, len) == 0) {
82426516Sbrian      if (cmds->alias[len] == '\0') {
82528679Sbrian	*pmatch = 1;
82628679Sbrian	return cmds;
82726516Sbrian      }
8286059Samurai      nmatch++;
8296059Samurai      found = cmds;
8306059Samurai    }
8316059Samurai    cmds++;
8326059Samurai  }
8336059Samurai  *pmatch = nmatch;
83426516Sbrian  return found;
8356059Samurai}
8366059Samurai
83736285Sbrianstatic const char *
83836285SbrianmkPrefix(int argc, char const *const *argv, char *tgt, int sz)
83936285Sbrian{
84036285Sbrian  int f, tlen, len;
84136285Sbrian
84236285Sbrian  tlen = 0;
84336285Sbrian  for (f = 0; f < argc && tlen < sz - 2; f++) {
84436285Sbrian    if (f)
84536285Sbrian      tgt[tlen++] = ' ';
84636285Sbrian    len = strlen(argv[f]);
84736285Sbrian    if (len > sz - tlen - 1)
84836285Sbrian      len = sz - tlen - 1;
84936285Sbrian    strncpy(tgt+tlen, argv[f], len);
85036285Sbrian    tlen += len;
85136285Sbrian  }
85236285Sbrian  tgt[tlen] = '\0';
85336285Sbrian  return tgt;
85436285Sbrian}
85536285Sbrian
85630715Sbrianstatic int
85736285SbrianFindExec(struct bundle *bundle, struct cmdtab const *cmds, int argc, int argn,
85836285Sbrian         char const *const *argv, struct prompt *prompt, struct datalink *cx)
8596059Samurai{
86028679Sbrian  struct cmdtab const *cmd;
8616059Samurai  int val = 1;
8626059Samurai  int nmatch;
86331343Sbrian  struct cmdargs arg;
86436285Sbrian  char prefix[100];
8656059Samurai
86636285Sbrian  cmd = FindCommand(cmds, argv[argn], &nmatch);
8676059Samurai  if (nmatch > 1)
86836285Sbrian    log_Printf(LogWARN, "%s: Ambiguous command\n",
86936285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix));
87036285Sbrian  else if (cmd && (!prompt || (cmd->lauth & prompt->auth))) {
87136285Sbrian    if ((cmd->lauth & LOCAL_CX) && !cx)
87236285Sbrian      /* We've got no context, but we require it */
87336285Sbrian      cx = bundle2datalink(bundle, NULL);
87436285Sbrian
87536285Sbrian    if ((cmd->lauth & LOCAL_CX) && !cx)
87636285Sbrian      log_Printf(LogWARN, "%s: No context (use the `link' command)\n",
87736285Sbrian                mkPrefix(argn+1, argv, prefix, sizeof prefix));
87836285Sbrian    else {
87936285Sbrian      if (cx && !(cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
88036285Sbrian        log_Printf(LogWARN, "%s: Redundant context (%s) ignored\n",
88136285Sbrian                  mkPrefix(argn+1, argv, prefix, sizeof prefix), cx->name);
88236285Sbrian        cx = NULL;
88336285Sbrian      }
88436285Sbrian      arg.cmdtab = cmds;
88536285Sbrian      arg.cmd = cmd;
88636285Sbrian      arg.argc = argc;
88736285Sbrian      arg.argn = argn+1;
88836285Sbrian      arg.argv = argv;
88936285Sbrian      arg.bundle = bundle;
89036285Sbrian      arg.cx = cx;
89136285Sbrian      arg.prompt = prompt;
89236285Sbrian      val = (*cmd->func) (&arg);
89336285Sbrian    }
89431343Sbrian  } else
89536285Sbrian    log_Printf(LogWARN, "%s: Invalid command\n",
89636285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix));
89726516Sbrian
89826516Sbrian  if (val == -1)
89936285Sbrian    log_Printf(LogWARN, "Usage: %s\n", cmd->syntax);
90028679Sbrian  else if (val)
90136285Sbrian    log_Printf(LogWARN, "%s: Failed %d\n",
90236285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix), val);
90326516Sbrian
90426516Sbrian  return val;
9056059Samurai}
9066059Samurai
90737009Sbrianint
90837009Sbriancommand_Interpret(char *buff, int nb, char *argv[MAXARGS])
9096059Samurai{
9106059Samurai  char *cp;
9116059Samurai
9126059Samurai  if (nb > 0) {
9136059Samurai    cp = buff + strcspn(buff, "\r\n");
9146059Samurai    if (cp)
9156059Samurai      *cp = '\0';
91637009Sbrian    return MakeArgs(buff, argv, MAXARGS);
91737009Sbrian  }
91837009Sbrian  return 0;
91931121Sbrian}
9206059Samurai
92131822Sbrianstatic int
92231822Sbrianarghidden(int argc, char const *const *argv, int n)
92331822Sbrian{
92431822Sbrian  /* Is arg n of the given command to be hidden from the log ? */
92531828Sbrian
92631828Sbrian  /* set authkey xxxxx */
92731828Sbrian  /* set key xxxxx */
92831822Sbrian  if (n == 2 && !strncasecmp(argv[0], "se", 2) &&
92931822Sbrian      (!strncasecmp(argv[1], "authk", 5) || !strncasecmp(argv[1], "ke", 2)))
93031822Sbrian    return 1;
93131822Sbrian
93231828Sbrian  /* passwd xxxxx */
93331828Sbrian  if (n == 1 && !strncasecmp(argv[0], "p", 1))
93431828Sbrian    return 1;
93531828Sbrian
93636285Sbrian  /* set server port xxxxx .... */
93736285Sbrian  if (n == 3 && !strncasecmp(argv[0], "se", 2) &&
93836285Sbrian      !strncasecmp(argv[1], "se", 2))
93936285Sbrian    return 1;
94036285Sbrian
94131822Sbrian  return 0;
94231822Sbrian}
94331822Sbrian
94431121Sbrianvoid
94536285Sbriancommand_Run(struct bundle *bundle, int argc, char const *const *argv,
94637008Sbrian           struct prompt *prompt, const char *label, struct datalink *cx)
94731121Sbrian{
94831156Sbrian  if (argc > 0) {
94936285Sbrian    if (log_IsKept(LogCOMMAND)) {
95047844Sbrian      char buf[LINE_LEN];
95131156Sbrian      int f, n;
95231156Sbrian
95331156Sbrian      if (label) {
95431962Sbrian        strncpy(buf, label, sizeof buf - 3);
95531962Sbrian        buf[sizeof buf - 3] = '\0';
95631156Sbrian        strcat(buf, ": ");
95747844Sbrian        n = strlen(buf);
95847844Sbrian      } else {
95947844Sbrian        *buf = '\0';
96047844Sbrian        n = 0;
96131156Sbrian      }
96247844Sbrian      buf[sizeof buf - 1] = '\0';	/* In case we run out of room in buf */
96347844Sbrian
96431156Sbrian      for (f = 0; f < argc; f++) {
96531962Sbrian        if (n < sizeof buf - 1 && f)
96631156Sbrian          buf[n++] = ' ';
96731822Sbrian        if (arghidden(argc, argv, f))
96836285Sbrian          strncpy(buf+n, "********", sizeof buf - n - 1);
96931822Sbrian        else
97031962Sbrian          strncpy(buf+n, argv[f], sizeof buf - n - 1);
97131156Sbrian        n += strlen(buf+n);
97231156Sbrian      }
97336285Sbrian      log_Printf(LogCOMMAND, "%s\n", buf);
97431156Sbrian    }
97537008Sbrian    FindExec(bundle, Commands, argc, 0, argv, prompt, cx);
97631156Sbrian  }
9776059Samurai}
9786059Samurai
97931121Sbrianvoid
98036285Sbriancommand_Decode(struct bundle *bundle, char *buff, int nb, struct prompt *prompt,
98136285Sbrian              const char *label)
98231121Sbrian{
98331121Sbrian  int argc;
98437009Sbrian  char *argv[MAXARGS];
98531121Sbrian
98637009Sbrian  argc = command_Interpret(buff, nb, argv);
98737008Sbrian  command_Run(bundle, argc, (char const *const *)argv, prompt, label, NULL);
98831121Sbrian}
98931121Sbrian
9906059Samuraistatic int
99131343SbrianShowCommand(struct cmdargs const *arg)
9926059Samurai{
99336285Sbrian  if (!arg->prompt)
99436285Sbrian    log_Printf(LogWARN, "show: Cannot show without a prompt\n");
99536285Sbrian  else if (arg->argc > arg->argn)
99636285Sbrian    FindExec(arg->bundle, ShowCommands, arg->argc, arg->argn, arg->argv,
99736285Sbrian             arg->prompt, arg->cx);
9986059Samurai  else
99936285Sbrian    prompt_Printf(arg->prompt, "Use ``show ?'' to get a list.\n");
100026516Sbrian
100126516Sbrian  return 0;
10026059Samurai}
10036059Samurai
10046059Samuraistatic int
100531343SbrianTerminalCommand(struct cmdargs const *arg)
10066059Samurai{
100736285Sbrian  if (!arg->prompt) {
100836285Sbrian    log_Printf(LogWARN, "term: Need a prompt\n");
100926516Sbrian    return 1;
10106059Samurai  }
101136285Sbrian
101236285Sbrian  if (arg->cx->physical->link.lcp.fsm.state > ST_CLOSED) {
101336285Sbrian    prompt_Printf(arg->prompt, "LCP state is [%s]\n",
101436285Sbrian                  State2Nam(arg->cx->physical->link.lcp.fsm.state));
101536285Sbrian    return 1;
10166059Samurai  }
101736285Sbrian
101836285Sbrian  datalink_Up(arg->cx, 0, 0);
101936285Sbrian  prompt_TtyTermMode(arg->prompt, arg->cx);
102036285Sbrian  return 0;
10216059Samurai}
10226059Samurai
10236059Samuraistatic int
102431343SbrianQuitCommand(struct cmdargs const *arg)
10256059Samurai{
102636285Sbrian  if (!arg->prompt || prompt_IsController(arg->prompt) ||
102736285Sbrian      (arg->argc > arg->argn && !strcasecmp(arg->argv[arg->argn], "all") &&
102836285Sbrian       (arg->prompt->auth & LOCAL_AUTH)))
102936285Sbrian    Cleanup(EX_NORMAL);
103036285Sbrian  if (arg->prompt)
103136285Sbrian    prompt_Destroy(arg->prompt, 1);
103226516Sbrian
103326516Sbrian  return 0;
10346059Samurai}
10356059Samurai
10366059Samuraistatic int
103736285SbrianOpenCommand(struct cmdargs const *arg)
10386059Samurai{
103937160Sbrian  if (arg->argc == arg->argn)
104037993Sbrian    bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1);
104137160Sbrian  else if (arg->argc == arg->argn + 1) {
104237160Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp")) {
104337385Sbrian      struct datalink *cx = arg->cx ?
104437385Sbrian        arg->cx : bundle2datalink(arg->bundle, NULL);
104537385Sbrian      if (cx) {
104637385Sbrian        if (cx->physical->link.lcp.fsm.state == ST_OPENED)
104737385Sbrian          fsm_Reopen(&cx->physical->link.lcp.fsm);
104837160Sbrian        else
104937993Sbrian          bundle_Open(arg->bundle, cx->name, PHYS_ALL, 1);
105037160Sbrian      } else
105137160Sbrian        log_Printf(LogWARN, "open lcp: You must specify a link\n");
105237160Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) {
105337160Sbrian      struct fsm *fp;
10546059Samurai
105537210Sbrian      fp = &command_ChooseLink(arg)->ccp.fsm;
105637160Sbrian      if (fp->link->lcp.fsm.state != ST_OPENED)
105737160Sbrian        log_Printf(LogWARN, "open: LCP must be open before opening CCP\n");
105837160Sbrian      else if (fp->state == ST_OPENED)
105937160Sbrian        fsm_Reopen(fp);
106037160Sbrian      else {
106137160Sbrian        fp->open_mode = 0;	/* Not passive any more */
106237160Sbrian        if (fp->state == ST_STOPPED) {
106337160Sbrian          fsm_Down(fp);
106437160Sbrian          fsm_Up(fp);
106537160Sbrian        } else {
106637160Sbrian          fsm_Up(fp);
106737160Sbrian          fsm_Open(fp);
106837160Sbrian        }
106936285Sbrian      }
107037160Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ipcp")) {
107137160Sbrian      if (arg->cx)
107237160Sbrian        log_Printf(LogWARN, "open ipcp: You need not specify a link\n");
107337160Sbrian      if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED)
107437160Sbrian        fsm_Reopen(&arg->bundle->ncp.ipcp.fsm);
107537160Sbrian      else
107637993Sbrian        bundle_Open(arg->bundle, NULL, PHYS_ALL, 1);
107737160Sbrian    } else
107837160Sbrian      return -1;
107936285Sbrian  } else
108036285Sbrian    return -1;
108136285Sbrian
108226516Sbrian  return 0;
10836059Samurai}
10846059Samurai
108525067Sbrianstatic int
108636285SbrianCloseCommand(struct cmdargs const *arg)
10876059Samurai{
108837007Sbrian  if (arg->argc == arg->argn)
108937007Sbrian    bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_STAYDOWN);
109037007Sbrian  else if (arg->argc == arg->argn + 1) {
109137007Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp"))
109237007Sbrian      bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_LCP);
109337007Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "ccp") ||
109437007Sbrian             !strcasecmp(arg->argv[arg->argn], "ccp!")) {
109537007Sbrian      struct fsm *fp;
10966059Samurai
109737210Sbrian      fp = &command_ChooseLink(arg)->ccp.fsm;
109837007Sbrian      if (fp->state == ST_OPENED) {
109937007Sbrian        fsm_Close(fp);
110037007Sbrian        if (arg->argv[arg->argn][3] == '!')
110137007Sbrian          fp->open_mode = 0;		/* Stay ST_CLOSED */
110237007Sbrian        else
110337007Sbrian          fp->open_mode = OPEN_PASSIVE;	/* Wait for the peer to start */
110437007Sbrian      }
110537007Sbrian    } else
110636285Sbrian      return -1;
110736285Sbrian  } else
110836285Sbrian    return -1;
110936285Sbrian
111036285Sbrian  return 0;
11116059Samurai}
11126059Samurai
111325067Sbrianstatic int
111436285SbrianDownCommand(struct cmdargs const *arg)
111511336Samurai{
111637018Sbrian  if (arg->argc == arg->argn) {
111737018Sbrian      if (arg->cx)
111837018Sbrian        datalink_Down(arg->cx, CLOSE_STAYDOWN);
111937018Sbrian      else
112037018Sbrian        bundle_Down(arg->bundle, CLOSE_STAYDOWN);
112137018Sbrian  } else if (arg->argc == arg->argn + 1) {
112237018Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp")) {
112337018Sbrian      if (arg->cx)
112437018Sbrian        datalink_Down(arg->cx, CLOSE_LCP);
112537018Sbrian      else
112637018Sbrian        bundle_Down(arg->bundle, CLOSE_LCP);
112737018Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) {
112837018Sbrian      struct fsm *fp = arg->cx ? &arg->cx->physical->link.ccp.fsm :
112937018Sbrian                                 &arg->bundle->ncp.mp.link.ccp.fsm;
113037060Sbrian      fsm2initial(fp);
113137018Sbrian    } else
113237018Sbrian      return -1;
113336285Sbrian  } else
113436285Sbrian    return -1;
113536285Sbrian
113636285Sbrian  return 0;
113725067Sbrian}
113825067Sbrian
113925067Sbrianstatic int
114036285SbrianSetModemSpeed(struct cmdargs const *arg)
114125067Sbrian{
114236285Sbrian  long speed;
114336285Sbrian  char *end;
114411336Samurai
114536285Sbrian  if (arg->argc > arg->argn && *arg->argv[arg->argn]) {
114636285Sbrian    if (arg->argc > arg->argn+1) {
114736285Sbrian      log_Printf(LogWARN, "SetModemSpeed: Too many arguments");
114836285Sbrian      return -1;
114911336Samurai    }
115036285Sbrian    if (strcasecmp(arg->argv[arg->argn], "sync") == 0) {
115136285Sbrian      physical_SetSync(arg->cx->physical);
115236285Sbrian      return 0;
115336285Sbrian    }
115436285Sbrian    end = NULL;
115536285Sbrian    speed = strtol(arg->argv[arg->argn], &end, 10);
115636285Sbrian    if (*end) {
115736285Sbrian      log_Printf(LogWARN, "SetModemSpeed: Bad argument \"%s\"",
115836285Sbrian                arg->argv[arg->argn]);
115936285Sbrian      return -1;
116036285Sbrian    }
116136285Sbrian    if (physical_SetSpeed(arg->cx->physical, speed))
116236285Sbrian      return 0;
116336285Sbrian    log_Printf(LogWARN, "%s: Invalid speed\n", arg->argv[arg->argn]);
116436285Sbrian  } else
116536285Sbrian    log_Printf(LogWARN, "SetModemSpeed: No speed specified\n");
116624939Sbrian
116726516Sbrian  return -1;
116811336Samurai}
116911336Samurai
117025067Sbrianstatic int
117131343SbrianSetStoppedTimeout(struct cmdargs const *arg)
117228327Sbrian{
117336285Sbrian  struct link *l = &arg->cx->physical->link;
117436285Sbrian
117536285Sbrian  l->lcp.fsm.StoppedTimer.load = 0;
117636285Sbrian  l->ccp.fsm.StoppedTimer.load = 0;
117736285Sbrian  if (arg->argc <= arg->argn+2) {
117836285Sbrian    if (arg->argc > arg->argn) {
117936285Sbrian      l->lcp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn]) * SECTICKS;
118036285Sbrian      if (arg->argc > arg->argn+1)
118136285Sbrian        l->ccp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn+1]) * SECTICKS;
118228461Sbrian    }
118328327Sbrian    return 0;
118428327Sbrian  }
118528327Sbrian  return -1;
118628327Sbrian}
118728327Sbrian
118828327Sbrianstatic int
118931343SbrianSetServer(struct cmdargs const *arg)
119026940Sbrian{
119126940Sbrian  int res = -1;
119226940Sbrian
119336285Sbrian  if (arg->argc > arg->argn && arg->argc < arg->argn+4) {
119431081Sbrian    const char *port, *passwd, *mask;
119553125Sbrian    int mlen;
119631081Sbrian
119731081Sbrian    /* What's what ? */
119836285Sbrian    port = arg->argv[arg->argn];
119936285Sbrian    if (arg->argc == arg->argn + 2) {
120036285Sbrian      passwd = arg->argv[arg->argn+1];
120136285Sbrian      mask = NULL;
120236285Sbrian    } else if (arg->argc == arg->argn + 3) {
120336285Sbrian      passwd = arg->argv[arg->argn+1];
120436285Sbrian      mask = arg->argv[arg->argn+2];
120553125Sbrian      mlen = strlen(mask);
120653125Sbrian      if (mlen == 0 || mlen > 4 || strspn(mask, "01234567") != mlen ||
120753125Sbrian          (mlen == 4 && *mask != '0')) {
120853125Sbrian        log_Printf(LogWARN, "%s %s: %s: Invalid mask\n",
120953125Sbrian                   arg->argv[arg->argn - 2], arg->argv[arg->argn - 1], mask);
121031081Sbrian        return -1;
121153125Sbrian      }
121236285Sbrian    } else if (strcasecmp(port, "none") == 0) {
121336285Sbrian      if (server_Close(arg->bundle))
121436285Sbrian        log_Printf(LogPHASE, "Disabled server port.\n");
121536285Sbrian      return 0;
121631081Sbrian    } else
121736285Sbrian      return -1;
121831081Sbrian
121936285Sbrian    strncpy(server.passwd, passwd, sizeof server.passwd - 1);
122036285Sbrian    server.passwd[sizeof server.passwd - 1] = '\0';
122131081Sbrian
122236285Sbrian    if (*port == '/') {
122331081Sbrian      mode_t imask;
122436285Sbrian      char *ptr, name[LINE_LEN + 12];
122528679Sbrian
122653125Sbrian      if (mask == NULL)
122731081Sbrian        imask = (mode_t)-1;
122853125Sbrian      else for (imask = mlen = 0; mask[mlen]; mlen++)
122953125Sbrian        imask = (imask * 8) + mask[mlen] - '0';
123036285Sbrian
123136285Sbrian      ptr = strstr(port, "%d");
123236285Sbrian      if (ptr) {
123336285Sbrian        snprintf(name, sizeof name, "%.*s%d%s",
123437210Sbrian                 (int)(ptr - port), port, arg->bundle->unit, ptr + 2);
123536285Sbrian        port = name;
123636285Sbrian      }
123736285Sbrian      res = server_LocalOpen(arg->bundle, port, imask);
123827346Sbrian    } else {
123936285Sbrian      int iport, add = 0;
124028679Sbrian
124131081Sbrian      if (mask != NULL)
124231081Sbrian        return -1;
124328679Sbrian
124436285Sbrian      if (*port == '+') {
124536285Sbrian        port++;
124636285Sbrian        add = 1;
124736285Sbrian      }
124831081Sbrian      if (strspn(port, "0123456789") != strlen(port)) {
124931081Sbrian        struct servent *s;
125031081Sbrian
125131081Sbrian        if ((s = getservbyname(port, "tcp")) == NULL) {
125231081Sbrian	  iport = 0;
125336285Sbrian	  log_Printf(LogWARN, "%s: Invalid port or service\n", port);
125428679Sbrian	} else
125531081Sbrian	  iport = ntohs(s->s_port);
125627346Sbrian      } else
125731081Sbrian        iport = atoi(port);
125836285Sbrian
125936285Sbrian      if (iport) {
126036285Sbrian        if (add)
126136285Sbrian          iport += arg->bundle->unit;
126236285Sbrian        res = server_TcpOpen(arg->bundle, iport);
126336285Sbrian      } else
126436285Sbrian        res = -1;
126527346Sbrian    }
126631081Sbrian  }
126726940Sbrian
126826940Sbrian  return res;
126926940Sbrian}
127026940Sbrian
127126940Sbrianstatic int
127231343SbrianSetEscape(struct cmdargs const *arg)
12736059Samurai{
12746059Samurai  int code;
127536285Sbrian  int argc = arg->argc - arg->argn;
127636285Sbrian  char const *const *argv = arg->argv + arg->argn;
12776059Samurai
12786059Samurai  for (code = 0; code < 33; code++)
127936285Sbrian    arg->cx->physical->async.cfg.EscMap[code] = 0;
128031343Sbrian
12816059Samurai  while (argc-- > 0) {
12826059Samurai    sscanf(*argv++, "%x", &code);
12836059Samurai    code &= 0xff;
128436285Sbrian    arg->cx->physical->async.cfg.EscMap[code >> 3] |= (1 << (code & 7));
128536285Sbrian    arg->cx->physical->async.cfg.EscMap[32] = 1;
12866059Samurai  }
128726516Sbrian  return 0;
12886059Samurai}
12896059Samurai
12906059Samuraistatic int
129131343SbrianSetInterfaceAddr(struct cmdargs const *arg)
12926059Samurai{
129336285Sbrian  struct ipcp *ipcp = &arg->bundle->ncp.ipcp;
129432267Sbrian  const char *hisaddr;
129532267Sbrian
129640561Sbrian  if (arg->argc > arg->argn + 4)
129740561Sbrian    return -1;
129840561Sbrian
129932267Sbrian  hisaddr = NULL;
130044874Sbrian  memset(&ipcp->cfg.my_range, '\0', sizeof ipcp->cfg.my_range);
130144874Sbrian  memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
130236285Sbrian  ipcp->cfg.HaveTriggerAddress = 0;
130336285Sbrian  ipcp->cfg.netmask.s_addr = INADDR_ANY;
130436285Sbrian  iplist_reset(&ipcp->cfg.peer_list);
130528394Sbrian
130636285Sbrian  if (arg->argc > arg->argn) {
130743313Sbrian    if (!ParseAddr(ipcp, arg->argv[arg->argn],
130836285Sbrian                   &ipcp->cfg.my_range.ipaddr, &ipcp->cfg.my_range.mask,
130936285Sbrian                   &ipcp->cfg.my_range.width))
131028679Sbrian      return 1;
131136285Sbrian    if (arg->argc > arg->argn+1) {
131236285Sbrian      hisaddr = arg->argv[arg->argn+1];
131336285Sbrian      if (arg->argc > arg->argn+2) {
131444455Sbrian        ipcp->ifmask = ipcp->cfg.netmask = GetIpAddr(arg->argv[arg->argn+2]);
131536285Sbrian	if (arg->argc > arg->argn+3) {
131636285Sbrian	  ipcp->cfg.TriggerAddress = GetIpAddr(arg->argv[arg->argn+3]);
131736285Sbrian	  ipcp->cfg.HaveTriggerAddress = 1;
13189440Samurai	}
13196059Samurai      }
13206059Samurai    }
13216059Samurai  }
132228394Sbrian
132340561Sbrian  /* 0.0.0.0 means any address (0 bits) */
132436285Sbrian  if (ipcp->cfg.my_range.ipaddr.s_addr == INADDR_ANY) {
132536285Sbrian    ipcp->cfg.my_range.mask.s_addr = INADDR_ANY;
132636285Sbrian    ipcp->cfg.my_range.width = 0;
13276059Samurai  }
132836285Sbrian  ipcp->my_ip.s_addr = ipcp->cfg.my_range.ipaddr.s_addr;
132947648Sbrian  bundle_AdjustFilters(arg->bundle, &ipcp->my_ip, NULL);
133036285Sbrian
133136285Sbrian  if (hisaddr && !ipcp_UseHisaddr(arg->bundle, hisaddr,
133236928Sbrian                                  arg->bundle->phys_type.all & PHYS_AUTO))
133332267Sbrian    return 4;
133431121Sbrian
133526516Sbrian  return 0;
13366059Samurai}
13376059Samurai
133818752Sjkhstatic int
133944305SbrianSetRetry(int argc, char const *const *argv, u_int *timeout, u_int *maxreq,
134044305Sbrian          u_int *maxtrm, int def)
134144305Sbrian{
134244305Sbrian  if (argc == 0) {
134344305Sbrian    *timeout = DEF_FSMRETRY;
134444305Sbrian    *maxreq = def;
134544305Sbrian    if (maxtrm != NULL)
134644305Sbrian      *maxtrm = def;
134744305Sbrian  } else {
134844305Sbrian    long l = atol(argv[0]);
134944305Sbrian
135044305Sbrian    if (l < MIN_FSMRETRY) {
135144305Sbrian      log_Printf(LogWARN, "%ld: Invalid FSM retry period - min %d\n",
135244305Sbrian                 l, MIN_FSMRETRY);
135344305Sbrian      return 1;
135444305Sbrian    } else
135544305Sbrian      *timeout = l;
135644305Sbrian
135744305Sbrian    if (argc > 1) {
135844305Sbrian      l = atol(argv[1]);
135944305Sbrian      if (l < 1) {
136044305Sbrian        log_Printf(LogWARN, "%ld: Invalid FSM REQ tries - changed to 1\n", l);
136144305Sbrian        l = 1;
136244305Sbrian      }
136344305Sbrian      *maxreq = l;
136444305Sbrian
136544305Sbrian      if (argc > 2 && maxtrm != NULL) {
136644305Sbrian        l = atol(argv[2]);
136744305Sbrian        if (l < 1) {
136844305Sbrian          log_Printf(LogWARN, "%ld: Invalid FSM TRM tries - changed to 1\n", l);
136944305Sbrian          l = 1;
137044305Sbrian        }
137144305Sbrian        *maxtrm = l;
137244305Sbrian      }
137344305Sbrian    }
137444305Sbrian  }
137544305Sbrian
137644305Sbrian  return 0;
137744305Sbrian}
137844305Sbrian
137944305Sbrianstatic int
138031343SbrianSetVariable(struct cmdargs const *arg)
13816059Samurai{
138237210Sbrian  long long_val, param = (long)arg->cmd->args;
138351048Sbrian  int mode, dummyint, f, first;
138431343Sbrian  const char *argp;
138536285Sbrian  struct datalink *cx = arg->cx;	/* LOCAL_CX uses this */
138636285Sbrian  const char *err = NULL;
138736285Sbrian  struct link *l = command_ChooseLink(arg);	/* LOCAL_CX_OPT uses this */
138836285Sbrian  struct in_addr dummyaddr, *addr;
13896059Samurai
139036285Sbrian  if (arg->argc > arg->argn)
139136285Sbrian    argp = arg->argv[arg->argn];
139226551Sbrian  else
139331343Sbrian    argp = "";
139426551Sbrian
139536285Sbrian  if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
139636285Sbrian    log_Printf(LogWARN, "set %s: No context (use the `link' command)\n",
139736285Sbrian              arg->cmd->name);
139836285Sbrian    return 1;
139936285Sbrian  } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
140036285Sbrian    log_Printf(LogWARN, "set %s: Redundant context (%s) ignored\n",
140136285Sbrian              arg->cmd->name, cx->name);
140236285Sbrian    cx = NULL;
140336285Sbrian  }
140436285Sbrian
140526551Sbrian  switch (param) {
140628679Sbrian  case VAR_AUTHKEY:
140750139Sbrian    strncpy(arg->bundle->cfg.auth.key, argp,
140850139Sbrian            sizeof arg->bundle->cfg.auth.key - 1);
140950139Sbrian    arg->bundle->cfg.auth.key[sizeof arg->bundle->cfg.auth.key - 1] = '\0';
141028679Sbrian    break;
141137210Sbrian
141228679Sbrian  case VAR_AUTHNAME:
141340622Sbrian    switch (bundle_Phase(arg->bundle)) {
141440622Sbrian      case PHASE_DEAD:
141540622Sbrian      case PHASE_ESTABLISH:
141640622Sbrian        strncpy(arg->bundle->cfg.auth.name, argp,
141740622Sbrian                sizeof arg->bundle->cfg.auth.name - 1);
141840622Sbrian        arg->bundle->cfg.auth.name[sizeof arg->bundle->cfg.auth.name-1] = '\0';
141940622Sbrian        break;
142040622Sbrian      default:
142140622Sbrian        err = "set authname: Only available at phase DEAD/ESTABLISH\n";
142240622Sbrian        log_Printf(LogWARN, err);
142340622Sbrian        break;
142436285Sbrian    }
142528679Sbrian    break;
142637210Sbrian
142736285Sbrian  case VAR_AUTOLOAD:
142849434Sbrian    if (arg->argc == arg->argn + 3) {
142949434Sbrian      int v1, v2, v3;
143049434Sbrian      char *end;
143149434Sbrian
143249434Sbrian      v1 = strtol(arg->argv[arg->argn], &end, 0);
143349434Sbrian      if (v1 < 0 || *end) {
143449434Sbrian        log_Printf(LogWARN, "autoload: %s: Invalid min percentage\n",
143549434Sbrian                   arg->argv[arg->argn]);
143649434Sbrian        return 1;
143736285Sbrian      }
143849434Sbrian
143949434Sbrian      v2 = strtol(arg->argv[arg->argn + 1], &end, 0);
144049434Sbrian      if (v2 < 0 || *end) {
144149434Sbrian        log_Printf(LogWARN, "autoload: %s: Invalid max percentage\n",
144249434Sbrian                   arg->argv[arg->argn + 1]);
144349434Sbrian        return 1;
144449434Sbrian      }
144549434Sbrian      if (v2 < v1) {
144649434Sbrian        v3 = v1;
144749434Sbrian        v1 = v2;
144849434Sbrian        v2 = v3;
144949434Sbrian      }
145049434Sbrian
145149434Sbrian      v3 = strtol(arg->argv[arg->argn + 2], &end, 0);
145249434Sbrian      if (v3 <= 0 || *end) {
145349434Sbrian        log_Printf(LogWARN, "autoload: %s: Invalid throughput period\n",
145449434Sbrian                   arg->argv[arg->argn + 2]);
145549434Sbrian        return 1;
145649434Sbrian      }
145749434Sbrian
145849434Sbrian      arg->bundle->ncp.mp.cfg.autoload.min = v1;
145949434Sbrian      arg->bundle->ncp.mp.cfg.autoload.max = v2;
146049434Sbrian      arg->bundle->ncp.mp.cfg.autoload.period = v3;
146149434Sbrian      mp_RestartAutoloadTimer(&arg->bundle->ncp.mp);
146236285Sbrian    } else {
146349434Sbrian      err = "Set autoload requires three arguments\n";
146436285Sbrian      log_Printf(LogWARN, err);
146536285Sbrian    }
146636285Sbrian    break;
146737210Sbrian
146828679Sbrian  case VAR_DIAL:
146936285Sbrian    strncpy(cx->cfg.script.dial, argp, sizeof cx->cfg.script.dial - 1);
147036285Sbrian    cx->cfg.script.dial[sizeof cx->cfg.script.dial - 1] = '\0';
147128679Sbrian    break;
147237210Sbrian
147328679Sbrian  case VAR_LOGIN:
147436285Sbrian    strncpy(cx->cfg.script.login, argp, sizeof cx->cfg.script.login - 1);
147536285Sbrian    cx->cfg.script.login[sizeof cx->cfg.script.login - 1] = '\0';
147628679Sbrian    break;
147737210Sbrian
147836285Sbrian  case VAR_WINSIZE:
147936285Sbrian    if (arg->argc > arg->argn) {
148036285Sbrian      l->ccp.cfg.deflate.out.winsize = atoi(arg->argv[arg->argn]);
148136285Sbrian      if (l->ccp.cfg.deflate.out.winsize < 8 ||
148236285Sbrian          l->ccp.cfg.deflate.out.winsize > 15) {
148336285Sbrian          log_Printf(LogWARN, "%d: Invalid outgoing window size\n",
148436285Sbrian                    l->ccp.cfg.deflate.out.winsize);
148536285Sbrian          l->ccp.cfg.deflate.out.winsize = 15;
148636285Sbrian      }
148736285Sbrian      if (arg->argc > arg->argn+1) {
148836285Sbrian        l->ccp.cfg.deflate.in.winsize = atoi(arg->argv[arg->argn+1]);
148936285Sbrian        if (l->ccp.cfg.deflate.in.winsize < 8 ||
149036285Sbrian            l->ccp.cfg.deflate.in.winsize > 15) {
149136285Sbrian            log_Printf(LogWARN, "%d: Invalid incoming window size\n",
149236285Sbrian                      l->ccp.cfg.deflate.in.winsize);
149336285Sbrian            l->ccp.cfg.deflate.in.winsize = 15;
149436285Sbrian        }
149536285Sbrian      } else
149636285Sbrian        l->ccp.cfg.deflate.in.winsize = 0;
149736285Sbrian    } else {
149836285Sbrian      err = "No window size specified\n";
149936285Sbrian      log_Printf(LogWARN, err);
150036285Sbrian    }
150136285Sbrian    break;
150237210Sbrian
150328679Sbrian  case VAR_DEVICE:
150436285Sbrian    physical_SetDeviceList(cx->physical, arg->argc - arg->argn,
150536285Sbrian                           arg->argv + arg->argn);
150636285Sbrian    break;
150737210Sbrian
150836285Sbrian  case VAR_ACCMAP:
150936285Sbrian    if (arg->argc > arg->argn) {
151037210Sbrian      u_long ulong_val;
151136285Sbrian      sscanf(argp, "%lx", &ulong_val);
151237210Sbrian      cx->physical->link.lcp.cfg.accmap = (u_int32_t)ulong_val;
151336285Sbrian    } else {
151436285Sbrian      err = "No accmap specified\n";
151536285Sbrian      log_Printf(LogWARN, err);
151636285Sbrian    }
151736285Sbrian    break;
151837210Sbrian
151936285Sbrian  case VAR_MODE:
152036285Sbrian    mode = Nam2mode(argp);
152136285Sbrian    if (mode == PHYS_NONE || mode == PHYS_ALL) {
152236285Sbrian      log_Printf(LogWARN, "%s: Invalid mode\n", argp);
152336285Sbrian      return -1;
152436285Sbrian    }
152536285Sbrian    bundle_SetMode(arg->bundle, cx, mode);
152636285Sbrian    break;
152737210Sbrian
152836285Sbrian  case VAR_MRRU:
152940622Sbrian    switch (bundle_Phase(arg->bundle)) {
153040622Sbrian      case PHASE_DEAD:
153140622Sbrian        break;
153240622Sbrian      case PHASE_ESTABLISH:
153340622Sbrian        /* Make sure none of our links are DATALINK_LCP or greater */
153440622Sbrian        if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) {
153540622Sbrian          log_Printf(LogWARN, "mrru: Only changable before LCP negotiations\n");
153640622Sbrian          return 1;
153740622Sbrian        }
153840622Sbrian        break;
153940622Sbrian      default:
154040622Sbrian        log_Printf(LogWARN, "mrru: Only changable at phase DEAD/ESTABLISH\n");
154140622Sbrian        return 1;
154229696Sbrian    }
154337210Sbrian    long_val = atol(argp);
154437210Sbrian    if (long_val && long_val < MIN_MRU) {
154537210Sbrian      log_Printf(LogWARN, "MRRU %ld: too small - min %d\n", long_val, MIN_MRU);
154637210Sbrian      return 1;
154737210Sbrian    } else if (long_val > MAX_MRU) {
154837210Sbrian      log_Printf(LogWARN, "MRRU %ld: too big - max %d\n", long_val, MAX_MRU);
154937210Sbrian      return 1;
155037210Sbrian    } else
155137210Sbrian      arg->bundle->ncp.mp.cfg.mrru = long_val;
155228679Sbrian    break;
155337210Sbrian
155436285Sbrian  case VAR_MRU:
155537210Sbrian    long_val = atol(argp);
155637210Sbrian    if (long_val == 0)
155737210Sbrian      l->lcp.cfg.mru = DEF_MRU;
155837210Sbrian    else if (long_val < MIN_MRU) {
155937210Sbrian      log_Printf(LogWARN, "MRU %ld: too small - min %d\n", long_val, MIN_MRU);
156037210Sbrian      return 1;
156137210Sbrian    } else if (long_val > MAX_MRU) {
156237210Sbrian      log_Printf(LogWARN, "MRU %ld: too big - max %d\n", long_val, MAX_MRU);
156337210Sbrian      return 1;
156437210Sbrian    } else
156537210Sbrian      l->lcp.cfg.mru = long_val;
156628679Sbrian    break;
156737210Sbrian
156836285Sbrian  case VAR_MTU:
156937210Sbrian    long_val = atol(argp);
157037210Sbrian    if (long_val && long_val < MIN_MTU) {
157137210Sbrian      log_Printf(LogWARN, "MTU %ld: too small - min %d\n", long_val, MIN_MTU);
157237210Sbrian      return 1;
157337210Sbrian    } else if (long_val > MAX_MTU) {
157437210Sbrian      log_Printf(LogWARN, "MTU %ld: too big - max %d\n", long_val, MAX_MTU);
157537210Sbrian      return 1;
157637210Sbrian    } else
157737210Sbrian      arg->bundle->cfg.mtu = long_val;
157836285Sbrian    break;
157937210Sbrian
158036285Sbrian  case VAR_OPENMODE:
158136285Sbrian    if (strcasecmp(argp, "active") == 0)
158236285Sbrian      cx->physical->link.lcp.cfg.openmode = arg->argc > arg->argn+1 ?
158336285Sbrian        atoi(arg->argv[arg->argn+1]) : 1;
158436285Sbrian    else if (strcasecmp(argp, "passive") == 0)
158536285Sbrian      cx->physical->link.lcp.cfg.openmode = OPEN_PASSIVE;
158636285Sbrian    else {
158736285Sbrian      err = "%s: Invalid openmode\n";
158836285Sbrian      log_Printf(LogWARN, err, argp);
158936285Sbrian    }
159036285Sbrian    break;
159137210Sbrian
159228679Sbrian  case VAR_PHONE:
159336285Sbrian    strncpy(cx->cfg.phone.list, argp, sizeof cx->cfg.phone.list - 1);
159436285Sbrian    cx->cfg.phone.list[sizeof cx->cfg.phone.list - 1] = '\0';
159538174Sbrian    cx->phone.alt = cx->phone.next = NULL;
159628679Sbrian    break;
159737210Sbrian
159828679Sbrian  case VAR_HANGUP:
159936285Sbrian    strncpy(cx->cfg.script.hangup, argp, sizeof cx->cfg.script.hangup - 1);
160036285Sbrian    cx->cfg.script.hangup[sizeof cx->cfg.script.hangup - 1] = '\0';
160128679Sbrian    break;
160237210Sbrian
160352488Sbrian  case VAR_LOGOUT:
160452488Sbrian    strncpy(cx->cfg.script.logout, argp, sizeof cx->cfg.script.logout - 1);
160552488Sbrian    cx->cfg.script.logout[sizeof cx->cfg.script.logout - 1] = '\0';
160652488Sbrian    break;
160752488Sbrian
160836285Sbrian  case VAR_IDLETIMEOUT:
160949978Sbrian    if (arg->argc > arg->argn+2)
161036285Sbrian      err = "Too many idle timeout values\n";
161149978Sbrian    else if (arg->argc == arg->argn)
161249978Sbrian      err = "Too few idle timeout values\n";
161349978Sbrian    else {
161449978Sbrian      int timeout, min;
161549978Sbrian
161649978Sbrian      timeout = atoi(argp);
161749978Sbrian      min = arg->argc == arg->argn + 2 ? atoi(arg->argv[arg->argn + 1]) : -1;
161849978Sbrian      bundle_SetIdleTimer(arg->bundle, timeout, min);
161949978Sbrian    }
162036285Sbrian    if (err)
162136285Sbrian      log_Printf(LogWARN, err);
162229549Sbrian    break;
162337210Sbrian
162436285Sbrian  case VAR_LQRPERIOD:
162537210Sbrian    long_val = atol(argp);
162637210Sbrian    if (long_val < MIN_LQRPERIOD) {
162737210Sbrian      log_Printf(LogWARN, "%ld: Invalid lqr period - min %d\n",
162837210Sbrian                 long_val, MIN_LQRPERIOD);
162937210Sbrian      return 1;
163036285Sbrian    } else
163137210Sbrian      l->lcp.cfg.lqrperiod = long_val;
163236285Sbrian    break;
163337210Sbrian
163436285Sbrian  case VAR_LCPRETRY:
163544305Sbrian    return SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
163644305Sbrian                    &cx->physical->link.lcp.cfg.fsm.timeout,
163744305Sbrian                    &cx->physical->link.lcp.cfg.fsm.maxreq,
163844305Sbrian                    &cx->physical->link.lcp.cfg.fsm.maxtrm, DEF_FSMTRIES);
163936285Sbrian    break;
164037210Sbrian
164136285Sbrian  case VAR_CHAPRETRY:
164244305Sbrian    return SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
164344305Sbrian                    &cx->chap.auth.cfg.fsm.timeout,
164444305Sbrian                    &cx->chap.auth.cfg.fsm.maxreq, NULL, DEF_FSMAUTHTRIES);
164536285Sbrian    break;
164637210Sbrian
164736285Sbrian  case VAR_PAPRETRY:
164844305Sbrian    return SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
164944305Sbrian                    &cx->pap.cfg.fsm.timeout, &cx->pap.cfg.fsm.maxreq,
165044305Sbrian                    NULL, DEF_FSMAUTHTRIES);
165136285Sbrian    break;
165237210Sbrian
165336285Sbrian  case VAR_CCPRETRY:
165444305Sbrian    return SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
165544305Sbrian                    &l->ccp.cfg.fsm.timeout, &l->ccp.cfg.fsm.maxreq,
165644305Sbrian                    &l->ccp.cfg.fsm.maxtrm, DEF_FSMTRIES);
165736285Sbrian    break;
165837210Sbrian
165936285Sbrian  case VAR_IPCPRETRY:
166044305Sbrian    return SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
166144305Sbrian                    &arg->bundle->ncp.ipcp.cfg.fsm.timeout,
166244305Sbrian                    &arg->bundle->ncp.ipcp.cfg.fsm.maxreq,
166344305Sbrian                    &arg->bundle->ncp.ipcp.cfg.fsm.maxtrm, DEF_FSMTRIES);
166436285Sbrian    break;
166537210Sbrian
166636285Sbrian  case VAR_NBNS:
166736285Sbrian  case VAR_DNS:
166836285Sbrian    if (param == VAR_DNS)
166936285Sbrian      addr = arg->bundle->ncp.ipcp.cfg.ns.dns;
167036285Sbrian    else
167136285Sbrian      addr = arg->bundle->ncp.ipcp.cfg.ns.nbns;
167236285Sbrian
167336285Sbrian    addr[0].s_addr = addr[1].s_addr = INADDR_ANY;
167436285Sbrian
167536285Sbrian    if (arg->argc > arg->argn) {
167643313Sbrian      ParseAddr(&arg->bundle->ncp.ipcp, arg->argv[arg->argn],
167736285Sbrian                addr, &dummyaddr, &dummyint);
167836285Sbrian      if (arg->argc > arg->argn+1)
167943313Sbrian        ParseAddr(&arg->bundle->ncp.ipcp, arg->argv[arg->argn + 1],
168036285Sbrian                  addr + 1, &dummyaddr, &dummyint);
168136285Sbrian
168236285Sbrian      if (addr[1].s_addr == INADDR_ANY)
168336285Sbrian        addr[1].s_addr = addr[0].s_addr;
168436285Sbrian      if (addr[0].s_addr == INADDR_ANY)
168536285Sbrian        addr[0].s_addr = addr[1].s_addr;
168636285Sbrian    }
168736285Sbrian    break;
168838174Sbrian
168938174Sbrian  case VAR_CALLBACK:
169038174Sbrian    cx->cfg.callback.opmask = 0;
169138174Sbrian    for (dummyint = arg->argn; dummyint < arg->argc; dummyint++) {
169238174Sbrian      if (!strcasecmp(arg->argv[dummyint], "auth"))
169338174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_AUTH);
169438174Sbrian      else if (!strcasecmp(arg->argv[dummyint], "cbcp"))
169538174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_CBCP);
169638174Sbrian      else if (!strcasecmp(arg->argv[dummyint], "e.164")) {
169738174Sbrian        if (dummyint == arg->argc - 1)
169838174Sbrian          log_Printf(LogWARN, "No E.164 arg (E.164 ignored) !\n");
169938174Sbrian        else {
170038174Sbrian          cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_E164);
170138174Sbrian          strncpy(cx->cfg.callback.msg, arg->argv[++dummyint],
170238174Sbrian                  sizeof cx->cfg.callback.msg - 1);
170338174Sbrian          cx->cfg.callback.msg[sizeof cx->cfg.callback.msg - 1] = '\0';
170438174Sbrian        }
170538174Sbrian      } else if (!strcasecmp(arg->argv[dummyint], "none"))
170638174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_NONE);
170738174Sbrian      else
170838174Sbrian        return -1;
170938174Sbrian    }
171038174Sbrian    if (cx->cfg.callback.opmask == CALLBACK_BIT(CALLBACK_NONE))
171138174Sbrian      cx->cfg.callback.opmask = 0;
171238174Sbrian    break;
171338174Sbrian
171438174Sbrian  case VAR_CBCP:
171538174Sbrian    cx->cfg.cbcp.delay = 0;
171638174Sbrian    *cx->cfg.cbcp.phone = '\0';
171738174Sbrian    cx->cfg.cbcp.fsmretry = DEF_FSMRETRY;
171838174Sbrian    if (arg->argc > arg->argn) {
171938174Sbrian      strncpy(cx->cfg.cbcp.phone, arg->argv[arg->argn],
172038174Sbrian              sizeof cx->cfg.cbcp.phone - 1);
172138174Sbrian      cx->cfg.cbcp.phone[sizeof cx->cfg.cbcp.phone - 1] = '\0';
172238174Sbrian      if (arg->argc > arg->argn + 1) {
172338174Sbrian        cx->cfg.cbcp.delay = atoi(arg->argv[arg->argn + 1]);
172438174Sbrian        if (arg->argc > arg->argn + 2) {
172538174Sbrian          long_val = atol(arg->argv[arg->argn + 2]);
172638174Sbrian          if (long_val < MIN_FSMRETRY)
172738174Sbrian            log_Printf(LogWARN, "%ld: Invalid CBCP FSM retry period - min %d\n",
172838174Sbrian                       long_val, MIN_FSMRETRY);
172938174Sbrian          else
173038174Sbrian            cx->cfg.cbcp.fsmretry = long_val;
173138174Sbrian        }
173238174Sbrian      }
173338174Sbrian    }
173438174Sbrian    break;
173538544Sbrian
173638544Sbrian  case VAR_CHOKED:
173738544Sbrian    arg->bundle->cfg.choked.timeout = atoi(argp);
173838544Sbrian    if (arg->bundle->cfg.choked.timeout <= 0)
173938544Sbrian      arg->bundle->cfg.choked.timeout = CHOKED_TIMEOUT;
174038544Sbrian    break;
174140665Sbrian
174240665Sbrian  case VAR_SENDPIPE:
174340665Sbrian    long_val = atol(argp);
174440665Sbrian    arg->bundle->ncp.ipcp.cfg.sendpipe = long_val;
174540665Sbrian    break;
174640665Sbrian
174740665Sbrian  case VAR_RECVPIPE:
174840665Sbrian    long_val = atol(argp);
174940665Sbrian    arg->bundle->ncp.ipcp.cfg.recvpipe = long_val;
175040665Sbrian    break;
175143313Sbrian
175243313Sbrian#ifndef NORADIUS
175343313Sbrian  case VAR_RADIUS:
175443313Sbrian    if (!*argp)
175543313Sbrian      *arg->bundle->radius.cfg.file = '\0';
175643313Sbrian    else if (access(argp, R_OK)) {
175743313Sbrian      log_Printf(LogWARN, "%s: %s\n", argp, strerror(errno));
175843313Sbrian      return 1;
175943313Sbrian    } else {
176043313Sbrian      strncpy(arg->bundle->radius.cfg.file, argp,
176143313Sbrian              sizeof arg->bundle->radius.cfg.file - 1);
176243313Sbrian      arg->bundle->radius.cfg.file
176343313Sbrian        [sizeof arg->bundle->radius.cfg.file - 1] = '\0';
176443313Sbrian    }
176543313Sbrian    break;
176643313Sbrian#endif
176744073Sbrian
176844073Sbrian  case VAR_CD:
176944073Sbrian    if (*argp) {
177051699Sbrian      if (strcasecmp(argp, "off")) {
177151699Sbrian        long_val = atol(argp);
177251699Sbrian        if (long_val < 0)
177351699Sbrian          long_val = 0;
177451699Sbrian        cx->physical->cfg.cd.delay = long_val;
177551699Sbrian        cx->physical->cfg.cd.necessity = argp[strlen(argp)-1] == '!' ?
177651699Sbrian          CD_REQUIRED : CD_VARIABLE;
177751699Sbrian      } else
177851699Sbrian        cx->physical->cfg.cd.necessity = CD_NOTREQUIRED;
177944073Sbrian    } else {
178053733Sbrian      cx->physical->cfg.cd.delay = 0;
178153733Sbrian      cx->physical->cfg.cd.necessity = CD_DEFAULT;
178244073Sbrian    }
178344073Sbrian    break;
178436285Sbrian
178546686Sbrian  case VAR_PARITY:
178646686Sbrian    if (arg->argc == arg->argn + 1)
178746686Sbrian      return physical_SetParity(arg->cx->physical, argp);
178846686Sbrian    else {
178946686Sbrian      err = "Parity value must be odd, even or none\n";
179046686Sbrian      log_Printf(LogWARN, err);
179146686Sbrian    }
179246686Sbrian    break;
17936059Samurai
179446686Sbrian  case VAR_CRTSCTS:
179546686Sbrian    if (strcasecmp(argp, "on") == 0)
179636285Sbrian      physical_SetRtsCts(arg->cx->physical, 1);
179746686Sbrian    else if (strcasecmp(argp, "off") == 0)
179836285Sbrian      physical_SetRtsCts(arg->cx->physical, 0);
179946686Sbrian    else {
180046686Sbrian      err = "RTS/CTS value must be on or off\n";
180146686Sbrian      log_Printf(LogWARN, err);
180246686Sbrian    }
180346686Sbrian    break;
180450867Sbrian
180550867Sbrian  case VAR_URGENTPORTS:
180651048Sbrian    if (arg->argn == arg->argc) {
180751048Sbrian      ipcp_ClearUrgentTcpPorts(&arg->bundle->ncp.ipcp);
180851048Sbrian      ipcp_ClearUrgentUdpPorts(&arg->bundle->ncp.ipcp);
180951048Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "udp")) {
181051048Sbrian      if (arg->argn == arg->argc - 1)
181151048Sbrian        ipcp_ClearUrgentUdpPorts(&arg->bundle->ncp.ipcp);
181251048Sbrian      else for (f = arg->argn + 1; f < arg->argc; f++)
181351048Sbrian        if (*arg->argv[f] == '+')
181451048Sbrian          ipcp_AddUrgentUdpPort(&arg->bundle->ncp.ipcp, atoi(arg->argv[f] + 1));
181551048Sbrian        else if (*arg->argv[f] == '-')
181651048Sbrian          ipcp_RemoveUrgentUdpPort(&arg->bundle->ncp.ipcp,
181751048Sbrian                                   atoi(arg->argv[f] + 1));
181851048Sbrian        else {
181951048Sbrian          if (f == arg->argn)
182051048Sbrian            ipcp_ClearUrgentUdpPorts(&arg->bundle->ncp.ipcp);
182151048Sbrian          ipcp_AddUrgentUdpPort(&arg->bundle->ncp.ipcp, atoi(arg->argv[f]));
182251048Sbrian        }
182351048Sbrian    } else {
182451048Sbrian      first = arg->argn;
182551048Sbrian      if (!strcasecmp(arg->argv[first], "tcp") && ++first == arg->argc)
182651048Sbrian        ipcp_ClearUrgentTcpPorts(&arg->bundle->ncp.ipcp);
182751048Sbrian
182851048Sbrian      for (f = first; f < arg->argc; f++)
182951048Sbrian        if (*arg->argv[f] == '+')
183051048Sbrian          ipcp_AddUrgentTcpPort(&arg->bundle->ncp.ipcp, atoi(arg->argv[f] + 1));
183151048Sbrian        else if (*arg->argv[f] == '-')
183251048Sbrian          ipcp_RemoveUrgentTcpPort(&arg->bundle->ncp.ipcp,
183351048Sbrian                                   atoi(arg->argv[f] + 1));
183451048Sbrian        else {
183551048Sbrian          if (f == first)
183651048Sbrian            ipcp_ClearUrgentTcpPorts(&arg->bundle->ncp.ipcp);
183751048Sbrian          ipcp_AddUrgentTcpPort(&arg->bundle->ncp.ipcp, atoi(arg->argv[f]));
183851048Sbrian        }
183951048Sbrian    }
184050867Sbrian    break;
184120812Sjkh  }
184246686Sbrian
184346686Sbrian  return err ? 1 : 0;
184420812Sjkh}
184520812Sjkh
184630715Sbrianstatic struct cmdtab const SetCommands[] = {
184736285Sbrian  {"accmap", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
184836285Sbrian  "accmap value", "set accmap hex-value", (const void *)VAR_ACCMAP},
184928679Sbrian  {"authkey", "key", SetVariable, LOCAL_AUTH,
185036285Sbrian  "authentication key", "set authkey|key key", (const void *)VAR_AUTHKEY},
185128679Sbrian  {"authname", NULL, SetVariable, LOCAL_AUTH,
185236285Sbrian  "authentication name", "set authname name", (const void *)VAR_AUTHNAME},
185336285Sbrian  {"autoload", NULL, SetVariable, LOCAL_AUTH,
185436285Sbrian  "auto link [de]activation", "set autoload maxtime maxload mintime minload",
185536285Sbrian  (const void *)VAR_AUTOLOAD},
185650867Sbrian  {"bandwidth", NULL, mp_SetDatalinkBandwidth, LOCAL_AUTH | LOCAL_CX,
185750867Sbrian  "datalink bandwidth", "set bandwidth value"},
185838174Sbrian  {"callback", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
185938174Sbrian  "callback control", "set callback [none|auth|cbcp|"
186038174Sbrian  "E.164 *|number[,number]...]...", (const void *)VAR_CALLBACK},
186138174Sbrian  {"cbcp", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
186238174Sbrian  "CBCP control", "set cbcp [*|phone[,phone...] [delay [timeout]]]",
186338174Sbrian  (const void *)VAR_CBCP},
186444305Sbrian  {"ccpretry", "ccpretries", SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
186544305Sbrian   "CCP retries", "set ccpretry value [attempts]", (const void *)VAR_CCPRETRY},
186644073Sbrian  {"cd", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "Carrier delay requirement",
186744073Sbrian   "set cd value[!]", (const void *)VAR_CD},
186844305Sbrian  {"chapretry", "chapretries", SetVariable, LOCAL_AUTH | LOCAL_CX,
186944305Sbrian   "CHAP retries", "set chapretry value [attempts]",
187044305Sbrian   (const void *)VAR_CHAPRETRY},
187138544Sbrian  {"choked", NULL, SetVariable, LOCAL_AUTH,
187238544Sbrian  "choked timeout", "set choked [secs]", (const void *)VAR_CHOKED},
187346686Sbrian  {"ctsrts", "crtscts", SetVariable, LOCAL_AUTH | LOCAL_CX,
187446686Sbrian   "Use hardware flow control", "set ctsrts [on|off]",
187546686Sbrian   (const char *)VAR_CRTSCTS},
187636285Sbrian  {"deflate", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
187736285Sbrian  "deflate window sizes", "set deflate out-winsize in-winsize",
187836285Sbrian  (const void *) VAR_WINSIZE},
187936285Sbrian  {"device", "line", SetVariable, LOCAL_AUTH | LOCAL_CX,
188046686Sbrian  "physical device name", "set device|line device-name[,device-name]",
188136285Sbrian  (const void *) VAR_DEVICE},
188236285Sbrian  {"dial", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
188336285Sbrian  "dialing script", "set dial chat-script", (const void *) VAR_DIAL},
188436285Sbrian  {"dns", NULL, SetVariable, LOCAL_AUTH, "Domain Name Server",
188536285Sbrian  "set dns pri-addr [sec-addr]", (const void *)VAR_DNS},
188636285Sbrian  {"enddisc", NULL, mp_SetEnddisc, LOCAL_AUTH,
188736285Sbrian  "Endpoint Discriminator", "set enddisc [IP|magic|label|psn value]"},
188836285Sbrian  {"escape", NULL, SetEscape, LOCAL_AUTH | LOCAL_CX,
188936285Sbrian  "escape characters", "set escape hex-digit ..."},
189036285Sbrian  {"filter", NULL, filter_Set, LOCAL_AUTH,
189136285Sbrian  "packet filters", "set filter alive|dial|in|out rule-no permit|deny "
189249388Sbrian  "[src_addr[/width]] [dst_addr[/width]] [tcp|udp|icmp|ospf|igmp "
189348142Sbrian  "[src [lt|eq|gt port]] [dst [lt|eq|gt port]] [estab] [syn] [finrst]]"},
189436285Sbrian  {"hangup", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
189536285Sbrian  "hangup script", "set hangup chat-script", (const void *) VAR_HANGUP},
189636285Sbrian  {"ifaddr", NULL, SetInterfaceAddr, LOCAL_AUTH, "destination address",
189731343Sbrian  "set ifaddr [src-addr [dst-addr [netmask [trg-addr]]]]"},
189844305Sbrian  {"ipcpretry", "ipcpretries", SetVariable, LOCAL_AUTH, "IPCP retries",
189944305Sbrian   "set ipcpretry value [attempts]", (const void *)VAR_IPCPRETRY},
190044305Sbrian  {"lcpretry", "lcpretries", SetVariable, LOCAL_AUTH | LOCAL_CX, "LCP retries",
190144305Sbrian   "set lcpretry value [attempts]", (const void *)VAR_LCPRETRY},
190236712Sbrian  {"log", NULL, log_SetLevel, LOCAL_AUTH, "log level",
190338622Sbrian  "set log [local] [+|-]async|cbcp|ccp|chat|command|connect|debug|hdlc|id0|"
190447699Sbrian  "ipcp|lcp|lqm|phase|physical|sync|tcp/ip|timer|tun..."},
190536285Sbrian  {"login", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
190636285Sbrian  "login script", "set login chat-script", (const void *) VAR_LOGIN},
190752488Sbrian  {"logout", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
190852488Sbrian  "logout script", "set logout chat-script", (const void *) VAR_LOGOUT},
190936285Sbrian  {"lqrperiod", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
191036285Sbrian  "LQR period", "set lqrperiod value", (const void *)VAR_LQRPERIOD},
191136285Sbrian  {"mode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "mode value",
191236285Sbrian  "set mode interactive|auto|ddial|background", (const void *)VAR_MODE},
191336285Sbrian  {"mrru", NULL, SetVariable, LOCAL_AUTH, "MRRU value",
191436285Sbrian  "set mrru value", (const void *)VAR_MRRU},
191536285Sbrian  {"mru", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
191636285Sbrian  "MRU value", "set mru value", (const void *)VAR_MRU},
191736285Sbrian  {"mtu", NULL, SetVariable, LOCAL_AUTH,
191836285Sbrian  "interface MTU value", "set mtu value", (const void *)VAR_MTU},
191936285Sbrian  {"nbns", NULL, SetVariable, LOCAL_AUTH, "NetBIOS Name Server",
192036285Sbrian  "set nbns pri-addr [sec-addr]", (const void *)VAR_NBNS},
192136285Sbrian  {"openmode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "open mode",
192236285Sbrian  "set openmode active|passive [secs]", (const void *)VAR_OPENMODE},
192344305Sbrian  {"papretry", "papretries", SetVariable, LOCAL_AUTH | LOCAL_CX, "PAP retries",
192444305Sbrian   "set papretry value [attempts]", (const void *)VAR_PAPRETRY},
192546686Sbrian  {"parity", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "serial parity",
192646686Sbrian   "set parity [odd|even|none]", (const void *)VAR_PARITY},
192736285Sbrian  {"phone", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "telephone number(s)",
192836285Sbrian  "set phone phone1[:phone2[...]]", (const void *)VAR_PHONE},
192940679Sbrian  {"proctitle", "title", SetProcTitle, LOCAL_AUTH,
193040679Sbrian  "Process title", "set proctitle [value]"},
193143313Sbrian#ifndef NORADIUS
193243313Sbrian  {"radius", NULL, SetVariable, LOCAL_AUTH,
193343313Sbrian  "RADIUS Config", "set radius cfgfile", (const void *)VAR_RADIUS},
193443313Sbrian#endif
193536285Sbrian  {"reconnect", NULL, datalink_SetReconnect, LOCAL_AUTH | LOCAL_CX,
193636285Sbrian  "Reconnect timeout", "set reconnect value ntries"},
193740665Sbrian  {"recvpipe", NULL, SetVariable, LOCAL_AUTH,
193840665Sbrian  "RECVPIPE value", "set recvpipe value", (const void *)VAR_RECVPIPE},
193936285Sbrian  {"redial", NULL, datalink_SetRedial, LOCAL_AUTH | LOCAL_CX,
194044468Sbrian  "Redial timeout", "set redial secs[+inc[-incmax]][.next] [attempts]"},
194140665Sbrian  {"sendpipe", NULL, SetVariable, LOCAL_AUTH,
194240665Sbrian  "SENDPIPE value", "set sendpipe value", (const void *)VAR_SENDPIPE},
194328679Sbrian  {"server", "socket", SetServer, LOCAL_AUTH,
194436774Sbrian  "server port", "set server|socket TcpPort|LocalName|none password [mask]"},
194536285Sbrian  {"speed", NULL, SetModemSpeed, LOCAL_AUTH | LOCAL_CX,
194646686Sbrian  "physical speed", "set speed value|sync"},
194736285Sbrian  {"stopped", NULL, SetStoppedTimeout, LOCAL_AUTH | LOCAL_CX,
194836285Sbrian  "STOPPED timeouts", "set stopped [LCPseconds [CCPseconds]]"},
194936285Sbrian  {"timeout", NULL, SetVariable, LOCAL_AUTH, "Idle timeout",
195036285Sbrian  "set timeout idletime", (const void *)VAR_IDLETIMEOUT},
195151048Sbrian  {"urgent", NULL, SetVariable, LOCAL_AUTH, "urgent ports",
195251048Sbrian  "set urgent [tcp|udp] [+|-]port...", (const void *)VAR_URGENTPORTS},
195336285Sbrian  {"vj", NULL, ipcp_vjset, LOCAL_AUTH,
195436285Sbrian  "vj values", "set vj slots|slotcomp [value]"},
195528679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
195631343Sbrian  "Display this message", "set help|? [command]", SetCommands},
195728679Sbrian  {NULL, NULL, NULL},
19586059Samurai};
19596059Samurai
19606059Samuraistatic int
196131343SbrianSetCommand(struct cmdargs const *arg)
19626059Samurai{
196336285Sbrian  if (arg->argc > arg->argn)
196436285Sbrian    FindExec(arg->bundle, SetCommands, arg->argc, arg->argn, arg->argv,
196536285Sbrian             arg->prompt, arg->cx);
196636285Sbrian  else if (arg->prompt)
196736285Sbrian    prompt_Printf(arg->prompt, "Use `set ?' to get a list or `set ? <var>' for"
196826516Sbrian	    " syntax help.\n");
19696059Samurai  else
197036285Sbrian    log_Printf(LogWARN, "set command must have arguments\n");
197126516Sbrian
197226516Sbrian  return 0;
19736059Samurai}
19746059Samurai
19756059Samuraistatic int
197631343SbrianAddCommand(struct cmdargs const *arg)
19776059Samurai{
19786059Samurai  struct in_addr dest, gateway, netmask;
197936285Sbrian  int gw, addrs;
19806059Samurai
198136285Sbrian  if (arg->argc != arg->argn+3 && arg->argc != arg->argn+2)
198231598Sbrian    return -1;
198331598Sbrian
198436285Sbrian  addrs = 0;
198536285Sbrian  if (arg->argc == arg->argn+2) {
198636285Sbrian    if (!strcasecmp(arg->argv[arg->argn], "default"))
198736285Sbrian      dest.s_addr = netmask.s_addr = INADDR_ANY;
198831598Sbrian    else {
198936285Sbrian      int width;
199036285Sbrian
199143313Sbrian      if (!ParseAddr(&arg->bundle->ncp.ipcp, arg->argv[arg->argn],
199236285Sbrian	             &dest, &netmask, &width))
199336285Sbrian        return -1;
199436285Sbrian      if (!strncasecmp(arg->argv[arg->argn], "MYADDR", 6))
199536285Sbrian        addrs = ROUTE_DSTMYADDR;
199636285Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "HISADDR", 7))
199736285Sbrian        addrs = ROUTE_DSTHISADDR;
199831598Sbrian    }
199936285Sbrian    gw = 1;
200034536Sbrian  } else {
200136285Sbrian    if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
200236285Sbrian      addrs = ROUTE_DSTMYADDR;
200336285Sbrian      dest = arg->bundle->ncp.ipcp.my_ip;
200436285Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
200536285Sbrian      addrs = ROUTE_DSTHISADDR;
200636285Sbrian      dest = arg->bundle->ncp.ipcp.peer_ip;
200736285Sbrian    } else
200836285Sbrian      dest = GetIpAddr(arg->argv[arg->argn]);
200936285Sbrian    netmask = GetIpAddr(arg->argv[arg->argn+1]);
201031598Sbrian    gw = 2;
20116059Samurai  }
201236285Sbrian
201336285Sbrian  if (strcasecmp(arg->argv[arg->argn+gw], "HISADDR") == 0) {
201436285Sbrian    gateway = arg->bundle->ncp.ipcp.peer_ip;
201536285Sbrian    addrs |= ROUTE_GWHISADDR;
201640561Sbrian  } else
201736285Sbrian    gateway = GetIpAddr(arg->argv[arg->argn+gw]);
201836285Sbrian
201936285Sbrian  if (bundle_SetRoute(arg->bundle, RTM_ADD, dest, gateway, netmask,
202043313Sbrian                  arg->cmd->args ? 1 : 0, (addrs & ROUTE_GWHISADDR) ? 1 : 0)
202143313Sbrian      && addrs != ROUTE_STATIC)
202236285Sbrian    route_Add(&arg->bundle->ncp.ipcp.route, addrs, dest, netmask, gateway);
202336285Sbrian
202431598Sbrian  return 0;
20256059Samurai}
20266059Samurai
20276059Samuraistatic int
202831343SbrianDeleteCommand(struct cmdargs const *arg)
20296059Samurai{
203031598Sbrian  struct in_addr dest, none;
203136285Sbrian  int addrs;
20326059Samurai
203336285Sbrian  if (arg->argc == arg->argn+1) {
203436285Sbrian    if(strcasecmp(arg->argv[arg->argn], "all") == 0) {
203536285Sbrian      route_IfDelete(arg->bundle, 0);
203636285Sbrian      route_DeleteAll(&arg->bundle->ncp.ipcp.route);
203736285Sbrian    } else {
203836285Sbrian      addrs = 0;
203936285Sbrian      if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
204036285Sbrian        dest = arg->bundle->ncp.ipcp.my_ip;
204136285Sbrian        addrs = ROUTE_DSTMYADDR;
204236285Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
204336285Sbrian        dest = arg->bundle->ncp.ipcp.peer_ip;
204436285Sbrian        addrs = ROUTE_DSTHISADDR;
204536285Sbrian      } else {
204644279Sbrian        dest = GetIpAddr(arg->argv[arg->argn]);
204744279Sbrian        if (dest.s_addr == INADDR_NONE) {
204844279Sbrian          log_Printf(LogWARN, "%s: Invalid IP address\n", arg->argv[arg->argn]);
204944279Sbrian          return -1;
205044279Sbrian        }
205136285Sbrian        addrs = ROUTE_STATIC;
205236285Sbrian      }
205331598Sbrian      none.s_addr = INADDR_ANY;
205436285Sbrian      bundle_SetRoute(arg->bundle, RTM_DELETE, dest, none, none,
205537927Sbrian                      arg->cmd->args ? 1 : 0, 0);
205636285Sbrian      route_Delete(&arg->bundle->ncp.ipcp.route, addrs, dest);
205731598Sbrian    }
205834536Sbrian  } else
205926516Sbrian    return -1;
206026516Sbrian
206126516Sbrian  return 0;
20626059Samurai}
20636059Samurai
206450059Sbrian#ifndef NONAT
206526031Sbrianstatic int
206631343SbrianAliasEnable(struct cmdargs const *arg)
206726031Sbrian{
206836285Sbrian  if (arg->argc == arg->argn+1) {
206936285Sbrian    if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
207050059Sbrian      if (!arg->bundle->NatEnabled) {
207146686Sbrian        if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED)
207246686Sbrian          PacketAliasSetAddress(arg->bundle->ncp.ipcp.my_ip);
207350059Sbrian        arg->bundle->NatEnabled = 1;
207446686Sbrian      }
207537191Sbrian      return 0;
207636285Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "no") == 0) {
207750059Sbrian      arg->bundle->NatEnabled = 0;
207840561Sbrian      arg->bundle->cfg.opt &= ~OPT_IFACEALIAS;
207940561Sbrian      /* Don't iface_Clear() - there may be manually configured addresses */
208026516Sbrian      return 0;
208126142Sbrian    }
208235449Sbrian  }
208336285Sbrian
208426516Sbrian  return -1;
208526031Sbrian}
208626031Sbrian
208726031Sbrian
208826031Sbrianstatic int
208931343SbrianAliasOption(struct cmdargs const *arg)
209026031Sbrian{
209138559Sbrian  long param = (long)arg->cmd->args;
209238559Sbrian
209336285Sbrian  if (arg->argc == arg->argn+1) {
209436285Sbrian    if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
209550059Sbrian      if (arg->bundle->NatEnabled) {
209637191Sbrian	PacketAliasSetMode(param, param);
209728679Sbrian	return 0;
209828679Sbrian      }
209950059Sbrian      log_Printf(LogWARN, "nat not enabled\n");
210036285Sbrian    } else if (strcmp(arg->argv[arg->argn], "no") == 0) {
210150059Sbrian      if (arg->bundle->NatEnabled) {
210237191Sbrian	PacketAliasSetMode(0, param);
210328679Sbrian	return 0;
210428679Sbrian      }
210550059Sbrian      log_Printf(LogWARN, "nat not enabled\n");
210628679Sbrian    }
210735449Sbrian  }
210828679Sbrian  return -1;
210926031Sbrian}
211050059Sbrian#endif /* #ifndef NONAT */
211131121Sbrian
211231121Sbrianstatic int
211336285SbrianLinkCommand(struct cmdargs const *arg)
211436285Sbrian{
211536285Sbrian  if (arg->argc > arg->argn+1) {
211636285Sbrian    char namelist[LINE_LEN];
211736285Sbrian    struct datalink *cx;
211836285Sbrian    char *name;
211936285Sbrian    int result = 0;
212036285Sbrian
212136285Sbrian    if (!strcmp(arg->argv[arg->argn], "*")) {
212236285Sbrian      struct datalink *dl;
212336285Sbrian
212436285Sbrian      cx = arg->bundle->links;
212536285Sbrian      while (cx) {
212636285Sbrian        /* Watch it, the command could be a ``remove'' */
212736285Sbrian        dl = cx->next;
212836285Sbrian        FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
212936285Sbrian                 arg->prompt, cx);
213036285Sbrian        for (cx = arg->bundle->links; cx; cx = cx->next)
213136285Sbrian          if (cx == dl)
213236285Sbrian            break;		/* Pointer's still valid ! */
213336285Sbrian      }
213436285Sbrian    } else {
213536285Sbrian      strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
213636285Sbrian      namelist[sizeof namelist - 1] = '\0';
213736285Sbrian      for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
213836285Sbrian        if (!bundle2datalink(arg->bundle, name)) {
213936285Sbrian          log_Printf(LogWARN, "link: %s: Invalid link name\n", name);
214036285Sbrian          return 1;
214136285Sbrian        }
214236285Sbrian
214336285Sbrian      strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
214436285Sbrian      namelist[sizeof namelist - 1] = '\0';
214536285Sbrian      for(name = strtok(namelist, ", "); name; name = strtok(NULL,", ")) {
214636285Sbrian        cx = bundle2datalink(arg->bundle, name);
214736285Sbrian        if (cx)
214836285Sbrian          FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
214936285Sbrian                   arg->prompt, cx);
215036285Sbrian        else {
215136285Sbrian          log_Printf(LogWARN, "link: %s: Invalidated link name !\n", name);
215236285Sbrian          result++;
215336285Sbrian        }
215436285Sbrian      }
215536285Sbrian    }
215636285Sbrian    return result;
215736285Sbrian  }
215836285Sbrian
215936285Sbrian  log_Printf(LogWARN, "Usage: %s\n", arg->cmd->syntax);
216036285Sbrian  return 2;
216136285Sbrian}
216236285Sbrian
216336285Sbrianstruct link *
216436285Sbriancommand_ChooseLink(struct cmdargs const *arg)
216536285Sbrian{
216636285Sbrian  if (arg->cx)
216736285Sbrian    return &arg->cx->physical->link;
216837210Sbrian  else if (!arg->bundle->ncp.mp.cfg.mrru) {
216936285Sbrian    struct datalink *dl = bundle2datalink(arg->bundle, NULL);
217037210Sbrian    if (dl)
217137210Sbrian      return &dl->physical->link;
217236285Sbrian  }
217337210Sbrian  return &arg->bundle->ncp.mp.link;
217436285Sbrian}
217536285Sbrian
217636285Sbrianstatic const char *
217736285Sbrianident_cmd(const char *cmd, unsigned *keep, unsigned *add)
217836285Sbrian{
217936285Sbrian  const char *result;
218036285Sbrian
218136285Sbrian  switch (*cmd) {
218236285Sbrian    case 'A':
218336285Sbrian    case 'a':
218436285Sbrian      result = "accept";
218536285Sbrian      *keep = NEG_MYMASK;
218636285Sbrian      *add = NEG_ACCEPTED;
218736285Sbrian      break;
218836285Sbrian    case 'D':
218936285Sbrian    case 'd':
219036285Sbrian      switch (cmd[1]) {
219136285Sbrian        case 'E':
219236285Sbrian        case 'e':
219336285Sbrian          result = "deny";
219436285Sbrian          *keep = NEG_MYMASK;
219536285Sbrian          *add = 0;
219636285Sbrian          break;
219736285Sbrian        case 'I':
219836285Sbrian        case 'i':
219936285Sbrian          result = "disable";
220036285Sbrian          *keep = NEG_HISMASK;
220136285Sbrian          *add = 0;
220236285Sbrian          break;
220336285Sbrian        default:
220436285Sbrian          return NULL;
220536285Sbrian      }
220636285Sbrian      break;
220736285Sbrian    case 'E':
220836285Sbrian    case 'e':
220936285Sbrian      result = "enable";
221036285Sbrian      *keep = NEG_HISMASK;
221136285Sbrian      *add = NEG_ENABLED;
221236285Sbrian      break;
221336285Sbrian    default:
221436285Sbrian      return NULL;
221536285Sbrian  }
221636285Sbrian
221736285Sbrian  return result;
221836285Sbrian}
221936285Sbrian
222036285Sbrianstatic int
222136285SbrianOptSet(struct cmdargs const *arg)
222236285Sbrian{
222337574Sbrian  int bit = (int)(long)arg->cmd->args;
222436285Sbrian  const char *cmd;
222536285Sbrian  unsigned keep;			/* Keep these bits */
222636285Sbrian  unsigned add;				/* Add these bits */
222736285Sbrian
222836285Sbrian  if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL)
222936285Sbrian    return 1;
223036285Sbrian
223136285Sbrian  if (add)
223236285Sbrian    arg->bundle->cfg.opt |= bit;
223336285Sbrian  else
223436285Sbrian    arg->bundle->cfg.opt &= ~bit;
223536285Sbrian  return 0;
223636285Sbrian}
223736285Sbrian
223836285Sbrianstatic int
223940561SbrianIfaceAliasOptSet(struct cmdargs const *arg)
224040561Sbrian{
224140561Sbrian  unsigned save = arg->bundle->cfg.opt;
224240561Sbrian  int result = OptSet(arg);
224340561Sbrian
224440561Sbrian  if (result == 0)
224550059Sbrian    if (Enabled(arg->bundle, OPT_IFACEALIAS) && !arg->bundle->NatEnabled) {
224640561Sbrian      arg->bundle->cfg.opt = save;
224750059Sbrian      log_Printf(LogWARN, "Cannot enable iface-alias without NAT\n");
224840561Sbrian      result = 2;
224940561Sbrian    }
225040561Sbrian
225140561Sbrian  return result;
225240561Sbrian}
225340561Sbrian
225440561Sbrianstatic int
225536285SbrianNegotiateSet(struct cmdargs const *arg)
225636285Sbrian{
225737210Sbrian  long param = (long)arg->cmd->args;
225836285Sbrian  struct link *l = command_ChooseLink(arg);	/* LOCAL_CX_OPT uses this */
225936285Sbrian  struct datalink *cx = arg->cx;	/* LOCAL_CX uses this */
226036285Sbrian  const char *cmd;
226136285Sbrian  unsigned keep;			/* Keep these bits */
226236285Sbrian  unsigned add;				/* Add these bits */
226336285Sbrian
226436285Sbrian  if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL)
226536285Sbrian    return 1;
226636285Sbrian
226736285Sbrian  if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
226836285Sbrian    log_Printf(LogWARN, "%s %s: No context (use the `link' command)\n",
226936285Sbrian              cmd, arg->cmd->name);
227036285Sbrian    return 2;
227136285Sbrian  } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
227236285Sbrian    log_Printf(LogWARN, "%s %s: Redundant context (%s) ignored\n",
227336285Sbrian              cmd, arg->cmd->name, cx->name);
227436285Sbrian    cx = NULL;
227536285Sbrian  }
227636285Sbrian
227736285Sbrian  switch (param) {
227836285Sbrian    case NEG_ACFCOMP:
227936285Sbrian      cx->physical->link.lcp.cfg.acfcomp &= keep;
228036285Sbrian      cx->physical->link.lcp.cfg.acfcomp |= add;
228136285Sbrian      break;
228244106Sbrian    case NEG_CHAP05:
228344106Sbrian      cx->physical->link.lcp.cfg.chap05 &= keep;
228444106Sbrian      cx->physical->link.lcp.cfg.chap05 |= add;
228536285Sbrian      break;
228644106Sbrian#ifdef HAVE_DES
228744106Sbrian    case NEG_CHAP80:
228844106Sbrian      cx->physical->link.lcp.cfg.chap80nt &= keep;
228944106Sbrian      cx->physical->link.lcp.cfg.chap80nt |= add;
229044106Sbrian      break;
229144106Sbrian    case NEG_CHAP80LM:
229244106Sbrian      cx->physical->link.lcp.cfg.chap80lm &= keep;
229344106Sbrian      cx->physical->link.lcp.cfg.chap80lm |= add;
229444106Sbrian      break;
229544106Sbrian#endif
229636285Sbrian    case NEG_DEFLATE:
229736285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE] &= keep;
229836285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE] |= add;
229936285Sbrian      break;
230036285Sbrian    case NEG_DNS:
230136285Sbrian      arg->bundle->ncp.ipcp.cfg.ns.dns_neg &= keep;
230236285Sbrian      arg->bundle->ncp.ipcp.cfg.ns.dns_neg |= add;
230336285Sbrian      break;
230447858Sbrian    case NEG_ENDDISC:
230547858Sbrian      arg->bundle->ncp.mp.cfg.negenddisc &= keep;
230647858Sbrian      arg->bundle->ncp.mp.cfg.negenddisc |= add;
230747858Sbrian      break;
230836285Sbrian    case NEG_LQR:
230936285Sbrian      cx->physical->link.lcp.cfg.lqr &= keep;
231036285Sbrian      cx->physical->link.lcp.cfg.lqr |= add;
231136285Sbrian      break;
231236285Sbrian    case NEG_PAP:
231336285Sbrian      cx->physical->link.lcp.cfg.pap &= keep;
231436285Sbrian      cx->physical->link.lcp.cfg.pap |= add;
231536285Sbrian      break;
231636285Sbrian    case NEG_PPPDDEFLATE:
231736285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE24] &= keep;
231836285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE24] |= add;
231936285Sbrian      break;
232036285Sbrian    case NEG_PRED1:
232136285Sbrian      l->ccp.cfg.neg[CCP_NEG_PRED1] &= keep;
232236285Sbrian      l->ccp.cfg.neg[CCP_NEG_PRED1] |= add;
232336285Sbrian      break;
232436285Sbrian    case NEG_PROTOCOMP:
232536285Sbrian      cx->physical->link.lcp.cfg.protocomp &= keep;
232636285Sbrian      cx->physical->link.lcp.cfg.protocomp |= add;
232736285Sbrian      break;
232836285Sbrian    case NEG_SHORTSEQ:
232940622Sbrian      switch (bundle_Phase(arg->bundle)) {
233040622Sbrian        case PHASE_DEAD:
233140622Sbrian          break;
233240622Sbrian        case PHASE_ESTABLISH:
233340622Sbrian          /* Make sure none of our links are DATALINK_LCP or greater */
233440622Sbrian          if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) {
233540622Sbrian            log_Printf(LogWARN, "shortseq: Only changable before"
233640622Sbrian                       " LCP negotiations\n");
233740622Sbrian            return 1;
233840622Sbrian          }
233940622Sbrian          break;
234040622Sbrian        default:
234140622Sbrian          log_Printf(LogWARN, "shortseq: Only changable at phase"
234240622Sbrian                     " DEAD/ESTABLISH\n");
234340622Sbrian          return 1;
234436285Sbrian      }
234540622Sbrian      arg->bundle->ncp.mp.cfg.shortseq &= keep;
234640622Sbrian      arg->bundle->ncp.mp.cfg.shortseq |= add;
234736285Sbrian      break;
234836285Sbrian    case NEG_VJCOMP:
234936285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.neg &= keep;
235036285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.neg |= add;
235136285Sbrian      break;
235236285Sbrian  }
235336285Sbrian
235436285Sbrian  return 0;
235536285Sbrian}
235636285Sbrian
235736285Sbrianstatic struct cmdtab const NegotiateCommands[] = {
235836285Sbrian  {"idcheck", NULL, OptSet, LOCAL_AUTH, "Check FSM reply ids",
235936285Sbrian  "disable|enable", (const void *)OPT_IDCHECK},
236040666Sbrian  {"iface-alias", NULL, IfaceAliasOptSet, LOCAL_AUTH,
236140666Sbrian   "retain interface addresses", "disable|enable",
236240666Sbrian   (const void *)OPT_IFACEALIAS},
236347689Sbrian  {"keep-session", NULL, OptSet, LOCAL_AUTH, "Retain device session leader",
236447689Sbrian  "disable|enable", (const void *)OPT_KEEPSESSION},
236536285Sbrian  {"loopback", NULL, OptSet, LOCAL_AUTH, "Loop packets for local iface",
236636285Sbrian  "disable|enable", (const void *)OPT_LOOPBACK},
236736285Sbrian  {"passwdauth", NULL, OptSet, LOCAL_AUTH, "Use passwd file",
236836285Sbrian  "disable|enable", (const void *)OPT_PASSWDAUTH},
236940665Sbrian  {"proxy", NULL, OptSet, LOCAL_AUTH, "Create a proxy ARP entry",
237036285Sbrian  "disable|enable", (const void *)OPT_PROXY},
237140665Sbrian  {"proxyall", NULL, OptSet, LOCAL_AUTH, "Proxy ARP for all remote hosts",
237240665Sbrian  "disable|enable", (const void *)OPT_PROXYALL},
237336285Sbrian  {"sroutes", NULL, OptSet, LOCAL_AUTH, "Use sticky routes",
237436285Sbrian  "disable|enable", (const void *)OPT_SROUTES},
237536285Sbrian  {"throughput", NULL, OptSet, LOCAL_AUTH, "Rolling throughput",
237636285Sbrian  "disable|enable", (const void *)OPT_THROUGHPUT},
237736285Sbrian  {"utmp", NULL, OptSet, LOCAL_AUTH, "Log connections in utmp",
237836285Sbrian  "disable|enable", (const void *)OPT_UTMP},
237936285Sbrian
238047689Sbrian#define OPT_MAX 10	/* accept/deny allowed below and not above */
238136285Sbrian
238236285Sbrian  {"acfcomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
238336285Sbrian  "Address & Control field compression", "accept|deny|disable|enable",
238436285Sbrian  (const void *)NEG_ACFCOMP},
238544106Sbrian  {"chap", "chap05", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
238636285Sbrian  "Challenge Handshake Authentication Protocol", "accept|deny|disable|enable",
238744106Sbrian  (const void *)NEG_CHAP05},
238844106Sbrian#ifdef HAVE_DES
238944106Sbrian  {"mschap", "chap80nt", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
239044106Sbrian  "Microsoft (NT) CHAP", "accept|deny|disable|enable",
239144106Sbrian  (const void *)NEG_CHAP80},
239244106Sbrian  {"LANMan", "chap80lm", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
239344106Sbrian  "Microsoft (NT) CHAP", "accept|deny|disable|enable",
239444106Sbrian  (const void *)NEG_CHAP80LM},
239544106Sbrian#endif
239636285Sbrian  {"deflate", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
239736285Sbrian  "Deflate compression", "accept|deny|disable|enable",
239836285Sbrian  (const void *)NEG_DEFLATE},
239936285Sbrian  {"deflate24", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
240036285Sbrian  "Deflate (type 24) compression", "accept|deny|disable|enable",
240136285Sbrian  (const void *)NEG_PPPDDEFLATE},
240236285Sbrian  {"dns", NULL, NegotiateSet, LOCAL_AUTH,
240336285Sbrian  "DNS specification", "accept|deny|disable|enable", (const void *)NEG_DNS},
240447858Sbrian  {"enddisc", NULL, NegotiateSet, LOCAL_AUTH, "ENDDISC negotiation",
240547858Sbrian  "accept|deny|disable|enable", (const void *)NEG_ENDDISC},
240636285Sbrian  {"lqr", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
240736285Sbrian  "Link Quality Reports", "accept|deny|disable|enable",
240836285Sbrian  (const void *)NEG_LQR},
240936285Sbrian  {"pap", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
241036285Sbrian  "Password Authentication protocol", "accept|deny|disable|enable",
241136285Sbrian  (const void *)NEG_PAP},
241236285Sbrian  {"pred1", "predictor1", NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
241336285Sbrian  "Predictor 1 compression", "accept|deny|disable|enable",
241436285Sbrian  (const void *)NEG_PRED1},
241536285Sbrian  {"protocomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
241636285Sbrian  "Protocol field compression", "accept|deny|disable|enable",
241736285Sbrian  (const void *)NEG_PROTOCOMP},
241836285Sbrian  {"shortseq", NULL, NegotiateSet, LOCAL_AUTH,
241936285Sbrian  "MP Short Sequence Numbers", "accept|deny|disable|enable",
242036285Sbrian  (const void *)NEG_SHORTSEQ},
242136285Sbrian  {"vjcomp", NULL, NegotiateSet, LOCAL_AUTH,
242236285Sbrian  "Van Jacobson header compression", "accept|deny|disable|enable",
242336285Sbrian  (const void *)NEG_VJCOMP},
242436285Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
242536285Sbrian  "Display this message", "accept|deny|disable|enable help|? [value]",
242636285Sbrian  NegotiateCommands},
242736285Sbrian  {NULL, NULL, NULL},
242836285Sbrian};
242936285Sbrian
243036285Sbrianstatic int
243136285SbrianNegotiateCommand(struct cmdargs const *arg)
243236285Sbrian{
243336285Sbrian  if (arg->argc > arg->argn) {
243436285Sbrian    char const *argv[3];
243536285Sbrian    unsigned keep, add;
243636285Sbrian    int n;
243736285Sbrian
243836285Sbrian    if ((argv[0] = ident_cmd(arg->argv[arg->argn-1], &keep, &add)) == NULL)
243936285Sbrian      return -1;
244036285Sbrian    argv[2] = NULL;
244136285Sbrian
244236285Sbrian    for (n = arg->argn; n < arg->argc; n++) {
244336285Sbrian      argv[1] = arg->argv[n];
244436285Sbrian      FindExec(arg->bundle, NegotiateCommands + (keep == NEG_HISMASK ?
244536285Sbrian               0 : OPT_MAX), 2, 1, argv, arg->prompt, arg->cx);
244636285Sbrian    }
244736285Sbrian  } else if (arg->prompt)
244836285Sbrian    prompt_Printf(arg->prompt, "Use `%s ?' to get a list.\n",
244936285Sbrian	    arg->argv[arg->argn-1]);
245036285Sbrian  else
245136285Sbrian    log_Printf(LogWARN, "%s command must have arguments\n",
245236285Sbrian              arg->argv[arg->argn] );
245336285Sbrian
245436285Sbrian  return 0;
245536285Sbrian}
245636285Sbrian
245736285Sbrianconst char *
245836285Sbriancommand_ShowNegval(unsigned val)
245936285Sbrian{
246036285Sbrian  switch (val&3) {
246136285Sbrian    case 1: return "disabled & accepted";
246236285Sbrian    case 2: return "enabled & denied";
246336285Sbrian    case 3: return "enabled & accepted";
246436285Sbrian  }
246536285Sbrian  return "disabled & denied";
246636285Sbrian}
246736934Sbrian
246836934Sbrianstatic int
246936934SbrianClearCommand(struct cmdargs const *arg)
247036934Sbrian{
247136934Sbrian  struct pppThroughput *t;
247236934Sbrian  struct datalink *cx;
247336934Sbrian  int i, clear_type;
247436934Sbrian
247536934Sbrian  if (arg->argc < arg->argn + 1)
247636934Sbrian    return -1;
247736934Sbrian
247846686Sbrian  if (strcasecmp(arg->argv[arg->argn], "physical") == 0) {
247936934Sbrian    cx = arg->cx;
248036934Sbrian    if (!cx)
248136934Sbrian      cx = bundle2datalink(arg->bundle, NULL);
248236934Sbrian    if (!cx) {
248346686Sbrian      log_Printf(LogWARN, "A link must be specified for ``clear physical''\n");
248436934Sbrian      return 1;
248536934Sbrian    }
248636934Sbrian    t = &cx->physical->link.throughput;
248736934Sbrian  } else if (strcasecmp(arg->argv[arg->argn], "ipcp") == 0)
248836934Sbrian    t = &arg->bundle->ncp.ipcp.throughput;
248936934Sbrian  else
249036934Sbrian    return -1;
249136934Sbrian
249236934Sbrian  if (arg->argc > arg->argn + 1) {
249336934Sbrian    clear_type = 0;
249436934Sbrian    for (i = arg->argn + 1; i < arg->argc; i++)
249536934Sbrian      if (strcasecmp(arg->argv[i], "overall") == 0)
249636934Sbrian        clear_type |= THROUGHPUT_OVERALL;
249736934Sbrian      else if (strcasecmp(arg->argv[i], "current") == 0)
249836934Sbrian        clear_type |= THROUGHPUT_CURRENT;
249936934Sbrian      else if (strcasecmp(arg->argv[i], "peak") == 0)
250036934Sbrian        clear_type |= THROUGHPUT_PEAK;
250136934Sbrian      else
250236934Sbrian        return -1;
250336934Sbrian  } else
250436934Sbrian    clear_type = THROUGHPUT_ALL;
250536934Sbrian
250636934Sbrian  throughput_clear(t, clear_type, arg->prompt);
250736934Sbrian  return 0;
250836934Sbrian}
250940561Sbrian
251040561Sbrianstatic int
251140561SbrianRunListCommand(struct cmdargs const *arg)
251240561Sbrian{
251340561Sbrian  const char *cmd = arg->argc ? arg->argv[arg->argc - 1] : "???";
251440561Sbrian
251540561Sbrian  if (arg->argc > arg->argn)
251640561Sbrian    FindExec(arg->bundle, arg->cmd->args, arg->argc, arg->argn, arg->argv,
251740561Sbrian             arg->prompt, arg->cx);
251840561Sbrian  else if (arg->prompt)
251940561Sbrian    prompt_Printf(arg->prompt, "Use `%s help' to get a list or `%s help"
252040561Sbrian                  " <option>' for syntax help.\n", cmd, cmd);
252140561Sbrian  else
252240561Sbrian    log_Printf(LogWARN, "%s command must have arguments\n", cmd);
252340561Sbrian
252440561Sbrian  return 0;
252540561Sbrian}
252640561Sbrian
252740561Sbrianstatic int
252840561SbrianIfaceAddCommand(struct cmdargs const *arg)
252940561Sbrian{
253040561Sbrian  int bits, n, how;
253140561Sbrian  struct in_addr ifa, mask, brd;
253240561Sbrian
253340664Sbrian  if (arg->argc == arg->argn + 1) {
253443313Sbrian    if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, NULL, NULL))
253540561Sbrian      return -1;
253640664Sbrian    mask.s_addr = brd.s_addr = INADDR_BROADCAST;
253740664Sbrian  } else {
253840664Sbrian    if (arg->argc == arg->argn + 2) {
253943313Sbrian      if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, &mask, &bits))
254040664Sbrian        return -1;
254140664Sbrian      n = 1;
254240664Sbrian    } else if (arg->argc == arg->argn + 3) {
254343313Sbrian      if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, NULL, NULL))
254440664Sbrian        return -1;
254543313Sbrian      if (!ParseAddr(NULL, arg->argv[arg->argn + 1], &mask, NULL, NULL))
254640664Sbrian        return -1;
254740664Sbrian      n = 2;
254840664Sbrian    } else
254940561Sbrian      return -1;
255040561Sbrian
255143313Sbrian    if (!ParseAddr(NULL, arg->argv[arg->argn + n], &brd, NULL, NULL))
255240664Sbrian      return -1;
255340664Sbrian  }
255440561Sbrian
255540561Sbrian  how = IFACE_ADD_LAST;
255640561Sbrian  if (arg->cmd->args)
255740561Sbrian    how |= IFACE_FORCE_ADD;
255840561Sbrian
255940561Sbrian  return !iface_inAdd(arg->bundle->iface, ifa, mask, brd, how);
256040561Sbrian}
256140561Sbrian
256240561Sbrianstatic int
256340561SbrianIfaceDeleteCommand(struct cmdargs const *arg)
256440561Sbrian{
256540561Sbrian  struct in_addr ifa;
256640561Sbrian  int ok;
256740561Sbrian
256840561Sbrian  if (arg->argc != arg->argn + 1)
256940561Sbrian    return -1;
257040561Sbrian
257143313Sbrian  if (!ParseAddr(NULL, arg->argv[arg->argn], &ifa, NULL, NULL))
257240561Sbrian    return -1;
257340561Sbrian
257440561Sbrian  if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED &&
257540561Sbrian      arg->bundle->ncp.ipcp.my_ip.s_addr == ifa.s_addr) {
257640561Sbrian    log_Printf(LogWARN, "%s: Cannot remove active interface address\n",
257740561Sbrian               inet_ntoa(ifa));
257840561Sbrian    return 1;
257940561Sbrian  }
258040561Sbrian
258140561Sbrian  ok = iface_inDelete(arg->bundle->iface, ifa);
258240561Sbrian  if (!ok) {
258340561Sbrian    if (arg->cmd->args)
258440561Sbrian      ok = 1;
258540561Sbrian    else if (arg->prompt)
258640561Sbrian      prompt_Printf(arg->prompt, "%s: No such address\n", inet_ntoa(ifa));
258740561Sbrian    else
258840561Sbrian      log_Printf(LogWARN, "%s: No such address\n", inet_ntoa(ifa));
258940561Sbrian  }
259040561Sbrian
259140561Sbrian  return !ok;
259240561Sbrian}
259340561Sbrian
259440561Sbrianstatic int
259540561SbrianIfaceClearCommand(struct cmdargs const *arg)
259640561Sbrian{
259740561Sbrian  int how;
259840561Sbrian
259940561Sbrian  if (arg->argc != arg->argn)
260040561Sbrian    return -1;
260140561Sbrian
260240941Sbrian  how = arg->bundle->ncp.ipcp.fsm.state == ST_OPENED ||
260340941Sbrian        arg->bundle->phys_type.all & PHYS_AUTO ?
260440561Sbrian        IFACE_CLEAR_ALIASES : IFACE_CLEAR_ALL;
260540561Sbrian  iface_Clear(arg->bundle->iface, how);
260640561Sbrian
260740561Sbrian  return 0;
260840561Sbrian}
260940679Sbrian
261040679Sbrianstatic int
261140679SbrianSetProcTitle(struct cmdargs const *arg)
261240679Sbrian{
261340679Sbrian  static char title[LINE_LEN];
261440679Sbrian  char *argv[MAXARGS], *ptr;
261540679Sbrian  int len, remaining, f, argc = arg->argc - arg->argn;
261640679Sbrian
261740679Sbrian  if (arg->argc == arg->argn) {
261853298Sbrian    ID0setproctitle(NULL);
261940679Sbrian    return 0;
262040679Sbrian  }
262140679Sbrian
262240679Sbrian  if (argc >= sizeof argv / sizeof argv[0]) {
262340679Sbrian    argc = sizeof argv / sizeof argv[0] - 1;
262440679Sbrian    log_Printf(LogWARN, "Truncating proc title to %d args\n", argc);
262540679Sbrian  }
262647849Sbrian  command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 1, getpid());
262740679Sbrian
262840679Sbrian  ptr = title;
262940679Sbrian  remaining = sizeof title - 1;
263040679Sbrian  for (f = 0; f < argc && remaining; f++) {
263140679Sbrian    if (f) {
263240679Sbrian      *ptr++ = ' ';
263340679Sbrian      remaining--;
263440679Sbrian    }
263540679Sbrian    len = strlen(argv[f]);
263640679Sbrian    if (len > remaining)
263740679Sbrian      len = remaining;
263840679Sbrian    memcpy(ptr, argv[f], len);
263940679Sbrian    remaining -= len;
264040679Sbrian    ptr += len;
264140679Sbrian  }
264240679Sbrian  *ptr = '\0';
264340679Sbrian
264453298Sbrian  ID0setproctitle(title);
264540679Sbrian
264640679Sbrian  return 0;
264740679Sbrian}
2648