command.c revision 86028
178189Sbrian/*-
278189Sbrian * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org>
378189Sbrian *          based on work by Toshiharu OHNO <tony-o@iij.ad.jp>
478189Sbrian *                           Internet Initiative Japan, Inc (IIJ)
578189Sbrian * All rights reserved.
66059Samurai *
778189Sbrian * Redistribution and use in source and binary forms, with or without
878189Sbrian * modification, are permitted provided that the following conditions
978189Sbrian * are met:
1078189Sbrian * 1. Redistributions of source code must retain the above copyright
1178189Sbrian *    notice, this list of conditions and the following disclaimer.
1278189Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1378189Sbrian *    notice, this list of conditions and the following disclaimer in the
1478189Sbrian *    documentation and/or other materials provided with the distribution.
156059Samurai *
1678189Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1778189Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1878189Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1978189Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2078189Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2178189Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2278189Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2378189Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2478189Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2578189Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2678189Sbrian * SUCH DAMAGE.
276059Samurai *
2850479Speter * $FreeBSD: head/usr.sbin/ppp/command.c 86028 2001-11-04 16:19:05Z brian $
296059Samurai */
3078189Sbrian
3143313Sbrian#include <sys/param.h>
3230715Sbrian#include <netinet/in_systm.h>
3326031Sbrian#include <netinet/in.h>
3430715Sbrian#include <netinet/ip.h>
3526031Sbrian#include <arpa/inet.h>
3630715Sbrian#include <sys/socket.h>
3726031Sbrian#include <net/route.h>
3830715Sbrian#include <netdb.h>
3936285Sbrian#include <sys/un.h>
4030715Sbrian
4138628Sbrian#include <ctype.h>
4230715Sbrian#include <errno.h>
4326516Sbrian#include <fcntl.h>
4430715Sbrian#include <paths.h>
4530715Sbrian#include <stdio.h>
4630715Sbrian#include <stdlib.h>
4730715Sbrian#include <string.h>
4830715Sbrian#include <sys/wait.h>
4930715Sbrian#include <termios.h>
5030715Sbrian#include <unistd.h>
5130715Sbrian
5250059Sbrian#ifndef NONAT
5358037Sbrian#ifdef LOCALNAT
5458037Sbrian#include "alias.h"
5558037Sbrian#else
5646086Sbrian#include <alias.h>
5739395Sbrian#endif
5839395Sbrian#endif
5958037Sbrian
6046686Sbrian#include "layer.h"
6137009Sbrian#include "defs.h"
6231343Sbrian#include "command.h"
6330715Sbrian#include "mbuf.h"
6430715Sbrian#include "log.h"
6530715Sbrian#include "timer.h"
666059Samurai#include "fsm.h"
6731690Sbrian#include "iplist.h"
6836285Sbrian#include "throughput.h"
6936285Sbrian#include "slcompress.h"
7038557Sbrian#include "lqr.h"
7138557Sbrian#include "hdlc.h"
7263484Sbrian#include "lcp.h"
7381634Sbrian#include "ncpaddr.h"
7481634Sbrian#include "ip.h"
756059Samurai#include "ipcp.h"
7650059Sbrian#ifndef NONAT
7751075Sbrian#include "nat_cmd.h"
7831343Sbrian#endif
7925630Sbrian#include "systems.h"
8036285Sbrian#include "filter.h"
8136285Sbrian#include "descriptor.h"
8230715Sbrian#include "main.h"
8330715Sbrian#include "route.h"
8430715Sbrian#include "ccp.h"
8531080Sbrian#include "auth.h"
8636285Sbrian#include "async.h"
8736285Sbrian#include "link.h"
8836285Sbrian#include "physical.h"
8936285Sbrian#include "mp.h"
9043313Sbrian#ifndef NORADIUS
9143313Sbrian#include "radius.h"
9243313Sbrian#endif
9381634Sbrian#include "ipv6cp.h"
9481634Sbrian#include "ncp.h"
9536285Sbrian#include "bundle.h"
9636285Sbrian#include "server.h"
9736285Sbrian#include "prompt.h"
9836285Sbrian#include "chat.h"
9936285Sbrian#include "chap.h"
10038174Sbrian#include "cbcp.h"
10136285Sbrian#include "datalink.h"
10240561Sbrian#include "iface.h"
10353298Sbrian#include "id.h"
10481697Sbrian#include "probe.h"
1056059Samurai
10636285Sbrian/* ``set'' values */
10736285Sbrian#define	VAR_AUTHKEY	0
10836285Sbrian#define	VAR_DIAL	1
10936285Sbrian#define	VAR_LOGIN	2
11036285Sbrian#define	VAR_AUTHNAME	3
11136285Sbrian#define	VAR_AUTOLOAD	4
11236285Sbrian#define	VAR_WINSIZE	5
11336285Sbrian#define	VAR_DEVICE	6
11436285Sbrian#define	VAR_ACCMAP	7
11536285Sbrian#define	VAR_MRRU	8
11636285Sbrian#define	VAR_MRU		9
11736285Sbrian#define	VAR_MTU		10
11836285Sbrian#define	VAR_OPENMODE	11
11936285Sbrian#define	VAR_PHONE	12
12036285Sbrian#define	VAR_HANGUP	13
12136285Sbrian#define	VAR_IDLETIMEOUT	14
12236285Sbrian#define	VAR_LQRPERIOD	15
12336285Sbrian#define	VAR_LCPRETRY	16
12436285Sbrian#define	VAR_CHAPRETRY	17
12536285Sbrian#define	VAR_PAPRETRY	18
12636285Sbrian#define	VAR_CCPRETRY	19
12736285Sbrian#define	VAR_IPCPRETRY	20
12836285Sbrian#define	VAR_DNS		21
12936285Sbrian#define	VAR_NBNS	22
13036285Sbrian#define	VAR_MODE	23
13138174Sbrian#define	VAR_CALLBACK	24
13238174Sbrian#define	VAR_CBCP	25
13338544Sbrian#define	VAR_CHOKED	26
13440665Sbrian#define	VAR_SENDPIPE	27
13540665Sbrian#define	VAR_RECVPIPE	28
13643313Sbrian#define	VAR_RADIUS	29
13744073Sbrian#define	VAR_CD		30
13846686Sbrian#define	VAR_PARITY	31
13946686Sbrian#define VAR_CRTSCTS	32
14050867Sbrian#define VAR_URGENTPORTS	33
14152488Sbrian#define	VAR_LOGOUT	34
14261534Sbrian#define	VAR_IFQUEUE	35
14378411Sbrian#define	VAR_MPPE	36
1446059Samurai
14536285Sbrian/* ``accept|deny|disable|enable'' masks */
14636285Sbrian#define NEG_HISMASK (1)
14736285Sbrian#define NEG_MYMASK (2)
14836285Sbrian
14936285Sbrian/* ``accept|deny|disable|enable'' values */
15036285Sbrian#define NEG_ACFCOMP	40
15144106Sbrian#define NEG_CHAP05	41
15244106Sbrian#define NEG_CHAP80	42
15344106Sbrian#define NEG_CHAP80LM	43
15444106Sbrian#define NEG_DEFLATE	44
15547858Sbrian#define NEG_DNS		45
15647858Sbrian#define NEG_ENDDISC	46
15747858Sbrian#define NEG_LQR		47
15847858Sbrian#define NEG_PAP		48
15947858Sbrian#define NEG_PPPDDEFLATE	49
16047858Sbrian#define NEG_PRED1	50
16147858Sbrian#define NEG_PROTOCOMP	51
16247858Sbrian#define NEG_SHORTSEQ	52
16347858Sbrian#define NEG_VJCOMP	53
16467910Sbrian#define NEG_MPPE	54
16567910Sbrian#define NEG_CHAP81	55
16636285Sbrian
16785362Sbrianconst char Version[] = "3.0.1";
16836285Sbrian
16936285Sbrianstatic int ShowCommand(struct cmdargs const *);
17036285Sbrianstatic int TerminalCommand(struct cmdargs const *);
17136285Sbrianstatic int QuitCommand(struct cmdargs const *);
17236285Sbrianstatic int OpenCommand(struct cmdargs const *);
17336285Sbrianstatic int CloseCommand(struct cmdargs const *);
17436285Sbrianstatic int DownCommand(struct cmdargs const *);
17536285Sbrianstatic int SetCommand(struct cmdargs const *);
17636285Sbrianstatic int LinkCommand(struct cmdargs const *);
17736285Sbrianstatic int AddCommand(struct cmdargs const *);
17836285Sbrianstatic int DeleteCommand(struct cmdargs const *);
17936285Sbrianstatic int NegotiateCommand(struct cmdargs const *);
18036934Sbrianstatic int ClearCommand(struct cmdargs const *);
18140561Sbrianstatic int RunListCommand(struct cmdargs const *);
18240561Sbrianstatic int IfaceAddCommand(struct cmdargs const *);
18340561Sbrianstatic int IfaceDeleteCommand(struct cmdargs const *);
18440561Sbrianstatic int IfaceClearCommand(struct cmdargs const *);
18540679Sbrianstatic int SetProcTitle(struct cmdargs const *);
18650059Sbrian#ifndef NONAT
18758867Sbrianstatic int NatEnable(struct cmdargs const *);
18858867Sbrianstatic int NatOption(struct cmdargs const *);
18931343Sbrian#endif
1906059Samurai
19136285Sbrianstatic const char *
19236285Sbrianshowcx(struct cmdtab const *cmd)
19336285Sbrian{
19436285Sbrian  if (cmd->lauth & LOCAL_CX)
19536285Sbrian    return "(c)";
19636285Sbrian  else if (cmd->lauth & LOCAL_CX_OPT)
19736285Sbrian    return "(o)";
19836285Sbrian
19936285Sbrian  return "";
20036285Sbrian}
20136285Sbrian
2026059Samuraistatic int
20331343SbrianHelpCommand(struct cmdargs const *arg)
2046059Samurai{
20528679Sbrian  struct cmdtab const *cmd;
20636285Sbrian  int n, cmax, dmax, cols, cxlen;
20736285Sbrian  const char *cx;
2086059Samurai
20936285Sbrian  if (!arg->prompt) {
21036285Sbrian    log_Printf(LogWARN, "help: Cannot help without a prompt\n");
21126516Sbrian    return 0;
21236285Sbrian  }
21326516Sbrian
21436285Sbrian  if (arg->argc > arg->argn) {
21536285Sbrian    for (cmd = arg->cmdtab; cmd->name || cmd->alias; cmd++)
21636285Sbrian      if ((cmd->lauth & arg->prompt->auth) &&
21736285Sbrian          ((cmd->name && !strcasecmp(cmd->name, arg->argv[arg->argn])) ||
21836285Sbrian           (cmd->alias && !strcasecmp(cmd->alias, arg->argv[arg->argn])))) {
21936285Sbrian	prompt_Printf(arg->prompt, "%s %s\n", cmd->syntax, showcx(cmd));
22028679Sbrian	return 0;
2216059Samurai      }
22226516Sbrian    return -1;
2236059Samurai  }
22436285Sbrian
22531372Sbrian  cmax = dmax = 0;
22636285Sbrian  for (cmd = arg->cmdtab; cmd->func; cmd++)
22736285Sbrian    if (cmd->name && (cmd->lauth & arg->prompt->auth)) {
22836285Sbrian      if ((n = strlen(cmd->name) + strlen(showcx(cmd))) > cmax)
22931372Sbrian        cmax = n;
23031372Sbrian      if ((n = strlen(cmd->helpmes)) > dmax)
23131372Sbrian        dmax = n;
23231372Sbrian    }
23331372Sbrian
23431372Sbrian  cols = 80 / (dmax + cmax + 3);
2356059Samurai  n = 0;
23636285Sbrian  prompt_Printf(arg->prompt, "(o) = Optional context,"
23736285Sbrian                " (c) = Context required\n");
23836285Sbrian  for (cmd = arg->cmdtab; cmd->func; cmd++)
23936285Sbrian    if (cmd->name && (cmd->lauth & arg->prompt->auth)) {
24036285Sbrian      cx = showcx(cmd);
24136285Sbrian      cxlen = cmax - strlen(cmd->name);
24240482Sbrian      if (n % cols != 0)
24340482Sbrian        prompt_Printf(arg->prompt, " ");
24440482Sbrian      prompt_Printf(arg->prompt, "%s%-*.*s: %-*.*s",
24536285Sbrian              cmd->name, cxlen, cxlen, cx, dmax, dmax, cmd->helpmes);
24631372Sbrian      if (++n % cols == 0)
24736285Sbrian        prompt_Printf(arg->prompt, "\n");
2486059Samurai    }
24931372Sbrian  if (n % cols != 0)
25036285Sbrian    prompt_Printf(arg->prompt, "\n");
25126516Sbrian
25226516Sbrian  return 0;
2536059Samurai}
2546059Samurai
25536285Sbrianstatic int
25663484SbrianIdentCommand(struct cmdargs const *arg)
25763484Sbrian{
25885991Sbrian  Concatinate(arg->cx->physical->link.lcp.cfg.ident,
25985991Sbrian              sizeof arg->cx->physical->link.lcp.cfg.ident,
26085991Sbrian              arg->argc - arg->argn, arg->argv + arg->argn);
26163484Sbrian  return 0;
26263484Sbrian}
26363484Sbrian
26463484Sbrianstatic int
26563484SbrianSendIdentification(struct cmdargs const *arg)
26663484Sbrian{
26763484Sbrian  if (arg->cx->state < DATALINK_LCP) {
26863484Sbrian    log_Printf(LogWARN, "sendident: link has not reached LCP\n");
26963484Sbrian    return 2;
27063484Sbrian  }
27163484Sbrian  return lcp_SendIdentification(&arg->cx->physical->link.lcp) ? 0 : 1;
27263484Sbrian}
27363484Sbrian
27463484Sbrianstatic int
27536285SbrianCloneCommand(struct cmdargs const *arg)
2766059Samurai{
27736285Sbrian  char namelist[LINE_LEN];
27836285Sbrian  char *name;
27936285Sbrian  int f;
2806059Samurai
28136285Sbrian  if (arg->argc == arg->argn)
28236285Sbrian    return -1;
28336285Sbrian
28436285Sbrian  namelist[sizeof namelist - 1] = '\0';
28536285Sbrian  for (f = arg->argn; f < arg->argc; f++) {
28636285Sbrian    strncpy(namelist, arg->argv[f], sizeof namelist - 1);
28736285Sbrian    for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
28836285Sbrian      bundle_DatalinkClone(arg->bundle, arg->cx, name);
2896059Samurai  }
29036285Sbrian
29136285Sbrian  return 0;
2926059Samurai}
2936059Samurai
2946059Samuraistatic int
29536285SbrianRemoveCommand(struct cmdargs const *arg)
2966059Samurai{
29736285Sbrian  if (arg->argc != arg->argn)
29836285Sbrian    return -1;
29911336Samurai
30036285Sbrian  if (arg->cx->state != DATALINK_CLOSED) {
30136285Sbrian    log_Printf(LogWARN, "remove: Cannot delete links that aren't closed\n");
30236285Sbrian    return 2;
3036059Samurai  }
30426516Sbrian
30536285Sbrian  bundle_DatalinkRemove(arg->bundle, arg->cx);
30636285Sbrian  return 0;
30736285Sbrian}
30832711Sbrian
30936285Sbrianstatic int
31036285SbrianRenameCommand(struct cmdargs const *arg)
31136285Sbrian{
31236285Sbrian  if (arg->argc != arg->argn + 1)
31336285Sbrian    return -1;
31431121Sbrian
31536285Sbrian  if (bundle_RenameDatalink(arg->bundle, arg->cx, arg->argv[arg->argn]))
31636285Sbrian    return 0;
31736285Sbrian
31836285Sbrian  log_Printf(LogWARN, "%s -> %s: target name already exists\n",
31936285Sbrian             arg->cx->name, arg->argv[arg->argn]);
32036285Sbrian  return 1;
32136285Sbrian}
32236285Sbrian
32385991Sbrianstatic int
32436285SbrianLoadCommand(struct cmdargs const *arg)
32536285Sbrian{
32640797Sbrian  const char *err;
32740797Sbrian  int n, mode;
32836285Sbrian
32940797Sbrian  mode = arg->bundle->phys_type.all;
33036285Sbrian
33140797Sbrian  if (arg->argn < arg->argc) {
33240797Sbrian    for (n = arg->argn; n < arg->argc; n++)
33340797Sbrian      if ((err = system_IsValid(arg->argv[n], arg->prompt, mode)) != NULL) {
33440797Sbrian        log_Printf(LogWARN, "%s: %s\n", arg->argv[n], err);
33540797Sbrian        return 1;
33640797Sbrian      }
33740797Sbrian
33840797Sbrian    for (n = arg->argn; n < arg->argc; n++) {
33940797Sbrian      bundle_SetLabel(arg->bundle, arg->argv[arg->argc - 1]);
34040797Sbrian      system_Select(arg->bundle, arg->argv[n], CONFFILE, arg->prompt, arg->cx);
34140797Sbrian    }
34240797Sbrian    bundle_SetLabel(arg->bundle, arg->argv[arg->argc - 1]);
34340797Sbrian  } else if ((err = system_IsValid("default", arg->prompt, mode)) != NULL) {
34440797Sbrian    log_Printf(LogWARN, "default: %s\n", err);
34536285Sbrian    return 1;
34636285Sbrian  } else {
34740797Sbrian    bundle_SetLabel(arg->bundle, "default");
34840797Sbrian    system_Select(arg->bundle, "default", CONFFILE, arg->prompt, arg->cx);
34940797Sbrian    bundle_SetLabel(arg->bundle, "default");
35036285Sbrian  }
35140797Sbrian
35226516Sbrian  return 0;
3536059Samurai}
3546059Samurai
35585991Sbrianstatic int
35685991SbrianLogCommand(struct cmdargs const *arg)
35785991Sbrian{
35885991Sbrian  char buf[LINE_LEN];
35985991Sbrian
36085991Sbrian  if (arg->argn < arg->argc) {
36185991Sbrian    char *argv[MAXARGS];
36285991Sbrian    int argc = arg->argc - arg->argn;
36385991Sbrian
36485991Sbrian    if (argc >= sizeof argv / sizeof argv[0]) {
36585991Sbrian      argc = sizeof argv / sizeof argv[0] - 1;
36685991Sbrian      log_Printf(LogWARN, "Truncating log command to %d args\n", argc);
36785991Sbrian    }
36885991Sbrian    command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 0, getpid());
36985991Sbrian    Concatinate(buf, sizeof buf, argc, (const char *const *)argv);
37085991Sbrian    log_Printf(LogLOG, "%s\n", buf);
37185991Sbrian    command_Free(argc, argv);
37285991Sbrian    return 0;
37385991Sbrian  }
37485991Sbrian
37585991Sbrian  return -1;
37685991Sbrian}
37785991Sbrian
37885991Sbrianstatic int
37936285SbrianSaveCommand(struct cmdargs const *arg)
38036285Sbrian{
38185991Sbrian  log_Printf(LogWARN, "save command is not yet implemented.\n");
38236285Sbrian  return 1;
38336285Sbrian}
38436285Sbrian
38510528Samuraistatic int
38636285SbrianDialCommand(struct cmdargs const *arg)
38728536Sbrian{
38836285Sbrian  int res;
38936285Sbrian
39036465Sbrian  if ((arg->cx && !(arg->cx->physical->type & (PHYS_INTERACTIVE|PHYS_AUTO)))
39136465Sbrian      || (!arg->cx &&
39236928Sbrian          (arg->bundle->phys_type.all & ~(PHYS_INTERACTIVE|PHYS_AUTO)))) {
39336285Sbrian    log_Printf(LogWARN, "Manual dial is only available for auto and"
39436285Sbrian              " interactive links\n");
39536285Sbrian    return 1;
39634536Sbrian  }
39736285Sbrian
39836285Sbrian  if (arg->argc > arg->argn && (res = LoadCommand(arg)) != 0)
39936285Sbrian    return res;
40036285Sbrian
40137993Sbrian  bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1);
40236285Sbrian
40336285Sbrian  return 0;
40428536Sbrian}
40528536Sbrian
40638628Sbrian#define isinword(ch) (isalnum(ch) || (ch) == '_')
40738628Sbrian
40838628Sbrianstatic char *
40938628Sbrianstrstrword(char *big, const char *little)
41038628Sbrian{
41138628Sbrian  /* Get the first occurance of the word ``little'' in ``big'' */
41238628Sbrian  char *pos;
41338628Sbrian  int len;
41438628Sbrian
41538628Sbrian  pos = big;
41638628Sbrian  len = strlen(little);
41738628Sbrian
41838628Sbrian  while ((pos = strstr(pos, little)) != NULL)
41947865Sbrian    if ((pos != big && isinword(pos[-1])) || isinword(pos[len]))
42047865Sbrian      pos++;
42147865Sbrian    else if (pos != big && pos[-1] == '\\')
42247865Sbrian      memmove(pos - 1, pos, strlen(pos) + 1);
42347865Sbrian    else
42438628Sbrian      break;
42538628Sbrian
42638628Sbrian  return pos;
42738628Sbrian}
42838628Sbrian
42938628Sbrianstatic char *
43038628Sbriansubst(char *tgt, const char *oldstr, const char *newstr)
43138628Sbrian{
43238628Sbrian  /* tgt is a malloc()d area... realloc() as necessary */
43338628Sbrian  char *word, *ntgt;
43438628Sbrian  int ltgt, loldstr, lnewstr, pos;
43538628Sbrian
43638628Sbrian  if ((word = strstrword(tgt, oldstr)) == NULL)
43738628Sbrian    return tgt;
43838628Sbrian
43938628Sbrian  ltgt = strlen(tgt) + 1;
44038628Sbrian  loldstr = strlen(oldstr);
44138628Sbrian  lnewstr = strlen(newstr);
44238628Sbrian  do {
44338628Sbrian    pos = word - tgt;
44438628Sbrian    if (loldstr > lnewstr)
44538628Sbrian      bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr);
44638628Sbrian    if (loldstr != lnewstr) {
44738628Sbrian      ntgt = realloc(tgt, ltgt += lnewstr - loldstr);
44838628Sbrian      if (ntgt == NULL)
44938628Sbrian        break;			/* Oh wonderful ! */
45038628Sbrian      word = ntgt + pos;
45138628Sbrian      tgt = ntgt;
45238628Sbrian    }
45338628Sbrian    if (lnewstr > loldstr)
45438628Sbrian      bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr);
45538628Sbrian    bcopy(newstr, word, lnewstr);
45638628Sbrian  } while ((word = strstrword(word, oldstr)));
45738628Sbrian
45838628Sbrian  return tgt;
45938628Sbrian}
46038628Sbrian
46143888Sbrianvoid
46243888Sbriancommand_Expand(char **nargv, int argc, char const *const *oargv,
46347849Sbrian               struct bundle *bundle, int inc0, pid_t pid)
46438628Sbrian{
46585991Sbrian  int arg, secs;
46685991Sbrian  char buf[20];
46747849Sbrian  char pidstr[12];
46838628Sbrian
46941755Sbrian  if (inc0)
47041755Sbrian    arg = 0;		/* Start at arg 0 */
47141755Sbrian  else {
47241755Sbrian    nargv[0] = strdup(oargv[0]);
47341755Sbrian    arg = 1;
47441755Sbrian  }
47547849Sbrian  snprintf(pidstr, sizeof pidstr, "%d", (int)pid);
47641755Sbrian  for (; arg < argc; arg++) {
47738629Sbrian    nargv[arg] = strdup(oargv[arg]);
47838629Sbrian    nargv[arg] = subst(nargv[arg], "HISADDR",
47938628Sbrian                       inet_ntoa(bundle->ncp.ipcp.peer_ip));
48081634Sbrian#ifndef NOINET6
48181897Sbrian    nargv[arg] = subst(nargv[arg], "HISADDR6",
48281897Sbrian                       ncpaddr_ntoa(&bundle->ncp.ipv6cp.hisaddr));
48381634Sbrian#endif
48438629Sbrian    nargv[arg] = subst(nargv[arg], "AUTHNAME", bundle->cfg.auth.name);
48540561Sbrian    nargv[arg] = subst(nargv[arg], "INTERFACE", bundle->iface->name);
48638628Sbrian    nargv[arg] = subst(nargv[arg], "MYADDR", inet_ntoa(bundle->ncp.ipcp.my_ip));
48781634Sbrian#ifndef NOINET6
48881897Sbrian    nargv[arg] = subst(nargv[arg], "MYADDR6",
48981897Sbrian                       ncpaddr_ntoa(&bundle->ncp.ipv6cp.myaddr));
49081634Sbrian#endif
49138629Sbrian    nargv[arg] = subst(nargv[arg], "USER", bundle->ncp.mp.peer.authname);
49238629Sbrian    nargv[arg] = subst(nargv[arg], "PEER_ENDDISC",
49338629Sbrian                       mp_Enddisc(bundle->ncp.mp.peer.enddisc.class,
49438629Sbrian                                  bundle->ncp.mp.peer.enddisc.address,
49538629Sbrian                                  bundle->ncp.mp.peer.enddisc.len));
49638629Sbrian    nargv[arg] = subst(nargv[arg], "ENDDISC",
49738629Sbrian                       mp_Enddisc(bundle->ncp.mp.cfg.enddisc.class,
49838629Sbrian                                  bundle->ncp.mp.cfg.enddisc.address,
49938629Sbrian                                  bundle->ncp.mp.cfg.enddisc.len));
50047849Sbrian    nargv[arg] = subst(nargv[arg], "PROCESSID", pidstr);
50138629Sbrian    nargv[arg] = subst(nargv[arg], "LABEL", bundle_GetLabel(bundle));
50258044Sbrian    nargv[arg] = subst(nargv[arg], "DNS0",
50358044Sbrian                       inet_ntoa(bundle->ncp.ipcp.ns.dns[0]));
50458044Sbrian    nargv[arg] = subst(nargv[arg], "DNS1",
50558044Sbrian                       inet_ntoa(bundle->ncp.ipcp.ns.dns[1]));
50663484Sbrian    nargv[arg] = subst(nargv[arg], "VERSION", Version);
50763484Sbrian    nargv[arg] = subst(nargv[arg], "COMPILATIONDATE", __DATE__);
50885991Sbrian
50985991Sbrian    secs = bundle_Uptime(bundle);
51085991Sbrian    snprintf(buf, sizeof buf, "%d:%02d:%02d", secs / 3600, (secs / 60) % 60,
51185991Sbrian             secs % 60);
51285991Sbrian    nargv[arg] = subst(nargv[arg], "UPTIME", buf);
51338628Sbrian  }
51438628Sbrian  nargv[arg] = NULL;
51538628Sbrian}
51638628Sbrian
51785991Sbrianvoid
51885991Sbriancommand_Free(int argc, char **argv)
51985991Sbrian{
52085991Sbrian  while (argc) {
52185991Sbrian    free(*argv);
52285991Sbrian    argc--;
52385991Sbrian    argv++;
52485991Sbrian  }
52585991Sbrian}
52685991Sbrian
52728536Sbrianstatic int
52831343SbrianShellCommand(struct cmdargs const *arg, int bg)
52910528Samurai{
53010528Samurai  const char *shell;
53147849Sbrian  pid_t shpid, pid;
53220813Sjkh
53318856Ssos#ifdef SHELL_ONLY_INTERACTIVELY
53426911Sbrian  /* we're only allowed to shell when we run ppp interactively */
53536285Sbrian  if (arg->prompt && arg->prompt->owner) {
53636285Sbrian    log_Printf(LogWARN, "Can't start a shell from a network connection\n");
53726516Sbrian    return 1;
53810528Samurai  }
53926911Sbrian#endif
54028679Sbrian
54136285Sbrian  if (arg->argc == arg->argn) {
54236285Sbrian    if (!arg->prompt) {
54336285Sbrian      log_Printf(LogWARN, "Can't start an interactive shell from"
54436285Sbrian                " a config file\n");
54528381Sbrian      return 1;
54636285Sbrian    } else if (arg->prompt->owner) {
54736285Sbrian      log_Printf(LogWARN, "Can't start an interactive shell from"
54836285Sbrian                " a socket connection\n");
54936285Sbrian      return 1;
55028381Sbrian    } else if (bg) {
55136285Sbrian      log_Printf(LogWARN, "Can only start an interactive shell in"
55228679Sbrian		" the foreground mode\n");
55328381Sbrian      return 1;
55428381Sbrian    }
55534536Sbrian  }
55634536Sbrian
55747849Sbrian  pid = getpid();
55828679Sbrian  if ((shpid = fork()) == 0) {
55936285Sbrian    int i, fd;
56018531Sbde
56136285Sbrian    if ((shell = getenv("SHELL")) == 0)
56236285Sbrian      shell = _PATH_BSHELL;
56332017Sbrian
56436285Sbrian    timer_TermService();
56536285Sbrian
56636285Sbrian    if (arg->prompt)
56736285Sbrian      fd = arg->prompt->fd_out;
56836285Sbrian    else if ((fd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
56936285Sbrian      log_Printf(LogALERT, "Failed to open %s: %s\n",
57036285Sbrian                _PATH_DEVNULL, strerror(errno));
57128679Sbrian      exit(1);
57228679Sbrian    }
57349976Sbrian    dup2(fd, STDIN_FILENO);
57449976Sbrian    dup2(fd, STDOUT_FILENO);
57549976Sbrian    dup2(fd, STDERR_FILENO);
57649976Sbrian    for (i = getdtablesize(); i > STDERR_FILENO; i--)
57749976Sbrian      fcntl(i, F_SETFD, 1);
57826516Sbrian
57964802Sbrian#ifndef NOSUID
58055252Sbrian    setuid(ID0realuid());
58164802Sbrian#endif
58236285Sbrian    if (arg->argc > arg->argn) {
58328679Sbrian      /* substitute pseudo args */
58438628Sbrian      char *argv[MAXARGS];
58538628Sbrian      int argc = arg->argc - arg->argn;
58638628Sbrian
58738628Sbrian      if (argc >= sizeof argv / sizeof argv[0]) {
58838628Sbrian        argc = sizeof argv / sizeof argv[0] - 1;
58938628Sbrian        log_Printf(LogWARN, "Truncating shell command to %d args\n", argc);
59031343Sbrian      }
59147849Sbrian      command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 0, pid);
59228679Sbrian      if (bg) {
59328679Sbrian	pid_t p;
59410528Samurai
59528679Sbrian	p = getpid();
59628679Sbrian	if (daemon(1, 1) == -1) {
59736832Sbrian	  log_Printf(LogERROR, "%d: daemon: %s\n", (int)p, strerror(errno));
59828679Sbrian	  exit(1);
59928679Sbrian	}
60036285Sbrian      } else if (arg->prompt)
60136285Sbrian        printf("ppp: Pausing until %s finishes\n", arg->argv[arg->argn]);
60231343Sbrian      execvp(argv[0], argv);
60330316Sbrian    } else {
60436285Sbrian      if (arg->prompt)
60532017Sbrian        printf("ppp: Pausing until %s finishes\n", shell);
60636285Sbrian      prompt_TtyOldMode(arg->prompt);
60779450Sbrian      execl(shell, shell, (char *)NULL);
60830316Sbrian    }
60920813Sjkh
61040665Sbrian    log_Printf(LogWARN, "exec() of %s failed: %s\n",
61140665Sbrian              arg->argc > arg->argn ? arg->argv[arg->argn] : shell,
61240665Sbrian              strerror(errno));
61349976Sbrian    _exit(255);
61410528Samurai  }
61536285Sbrian
61636285Sbrian  if (shpid == (pid_t) - 1)
61736285Sbrian    log_Printf(LogERROR, "Fork failed: %s\n", strerror(errno));
61836285Sbrian  else {
61910528Samurai    int status;
62031343Sbrian    waitpid(shpid, &status, 0);
62110528Samurai  }
62220813Sjkh
62336285Sbrian  if (arg->prompt && !arg->prompt->owner)
62436285Sbrian    prompt_TtyCommandMode(arg->prompt);
62520813Sjkh
62636285Sbrian  return 0;
62710528Samurai}
62810528Samurai
62931343Sbrianstatic int
63031343SbrianBgShellCommand(struct cmdargs const *arg)
63131343Sbrian{
63236285Sbrian  if (arg->argc == arg->argn)
63331343Sbrian    return -1;
63431343Sbrian  return ShellCommand(arg, 1);
63531343Sbrian}
63631343Sbrian
63731343Sbrianstatic int
63831343SbrianFgShellCommand(struct cmdargs const *arg)
63931343Sbrian{
64031343Sbrian  return ShellCommand(arg, 0);
64131343Sbrian}
64231343Sbrian
64358044Sbrianstatic int
64458044SbrianResolvCommand(struct cmdargs const *arg)
64558044Sbrian{
64658044Sbrian  if (arg->argc == arg->argn + 1) {
64758044Sbrian    if (!strcasecmp(arg->argv[arg->argn], "reload"))
64858044Sbrian      ipcp_LoadDNS(&arg->bundle->ncp.ipcp);
64958044Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "restore"))
65058044Sbrian      ipcp_RestoreDNS(&arg->bundle->ncp.ipcp);
65158044Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "rewrite"))
65258044Sbrian      ipcp_WriteDNS(&arg->bundle->ncp.ipcp);
65358044Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "readonly"))
65458044Sbrian      arg->bundle->ncp.ipcp.ns.writable = 0;
65558044Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "writable"))
65658044Sbrian      arg->bundle->ncp.ipcp.ns.writable = 1;
65758044Sbrian    else
65858044Sbrian      return -1;
65958044Sbrian
66058044Sbrian    return 0;
66158044Sbrian  }
66258044Sbrian
66358044Sbrian  return -1;
66458044Sbrian}
66558044Sbrian
66650059Sbrian#ifndef NONAT
66758867Sbrianstatic struct cmdtab const NatCommands[] =
66840561Sbrian{
66950059Sbrian  {"addr", NULL, nat_RedirectAddr, LOCAL_AUTH,
67050059Sbrian   "static address translation", "nat addr [addr_local addr_alias]"},
67158867Sbrian  {"deny_incoming", NULL, NatOption, LOCAL_AUTH,
67250059Sbrian   "stop incoming connections", "nat deny_incoming yes|no",
67340561Sbrian   (const void *) PKT_ALIAS_DENY_INCOMING},
67458867Sbrian  {"enable", NULL, NatEnable, LOCAL_AUTH,
67550059Sbrian   "enable NAT", "nat enable yes|no"},
67658867Sbrian  {"log", NULL, NatOption, LOCAL_AUTH,
67750059Sbrian   "log NAT link creation", "nat log yes|no",
67840561Sbrian   (const void *) PKT_ALIAS_LOG},
67950059Sbrian  {"port", NULL, nat_RedirectPort, LOCAL_AUTH, "port redirection",
68050059Sbrian   "nat port proto localaddr:port[-port] aliasport[-aliasport]"},
68179433Sbrian  {"proto", NULL, nat_RedirectProto, LOCAL_AUTH, "protocol redirection",
68279433Sbrian   "nat proto proto localIP [publicIP [remoteIP]]"},
68350059Sbrian  {"proxy", NULL, nat_ProxyRule, LOCAL_AUTH,
68450059Sbrian   "proxy control", "nat proxy server host[:port] ..."},
68581033Sbrian#ifndef NO_FW_PUNCH
68681033Sbrian  {"punch_fw", NULL, nat_PunchFW, LOCAL_AUTH,
68781033Sbrian   "firewall control", "nat punch_fw [base count]"},
68881033Sbrian#endif
68958867Sbrian  {"same_ports", NULL, NatOption, LOCAL_AUTH,
69050059Sbrian   "try to leave port numbers unchanged", "nat same_ports yes|no",
69140561Sbrian   (const void *) PKT_ALIAS_SAME_PORTS},
69258867Sbrian  {"target", NULL, nat_SetTarget, LOCAL_AUTH,
69358867Sbrian   "Default address for incoming connections", "nat target addr" },
69458867Sbrian  {"unregistered_only", NULL, NatOption, LOCAL_AUTH,
69550059Sbrian   "translate unregistered (private) IP address space only",
69650059Sbrian   "nat unregistered_only yes|no",
69740561Sbrian   (const void *) PKT_ALIAS_UNREGISTERED_ONLY},
69858867Sbrian  {"use_sockets", NULL, NatOption, LOCAL_AUTH,
69950059Sbrian   "allocate host sockets", "nat use_sockets yes|no",
70040561Sbrian   (const void *) PKT_ALIAS_USE_SOCKETS},
70140561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
70258867Sbrian   "Display this message", "nat help|? [command]", NatCommands},
70340561Sbrian  {NULL, NULL, NULL},
70440561Sbrian};
70540561Sbrian#endif
70640561Sbrian
70740561Sbrianstatic struct cmdtab const AllowCommands[] = {
70840561Sbrian  {"modes", "mode", AllowModes, LOCAL_AUTH,
70940561Sbrian  "Only allow certain ppp modes", "allow modes mode..."},
71040561Sbrian  {"users", "user", AllowUsers, LOCAL_AUTH,
71140561Sbrian  "Only allow ppp access to certain users", "allow users logname..."},
71240561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
71340561Sbrian  "Display this message", "allow help|? [command]", AllowCommands},
71440561Sbrian  {NULL, NULL, NULL},
71540561Sbrian};
71640561Sbrian
71740561Sbrianstatic struct cmdtab const IfaceCommands[] =
71840561Sbrian{
71940561Sbrian  {"add", NULL, IfaceAddCommand, LOCAL_AUTH,
72040561Sbrian   "Add iface address", "iface add addr[/bits| mask] peer", NULL},
72140561Sbrian  {NULL, "add!", IfaceAddCommand, LOCAL_AUTH,
72240561Sbrian   "Add or change an iface address", "iface add! addr[/bits| mask] peer",
72340561Sbrian   (void *)1},
72440561Sbrian  {"clear", NULL, IfaceClearCommand, LOCAL_AUTH,
72581634Sbrian   "Clear iface address(es)", "iface clear [INET | INET6]"},
72640561Sbrian  {"delete", "rm", IfaceDeleteCommand, LOCAL_AUTH,
72740561Sbrian   "Delete iface address", "iface delete addr", NULL},
72840561Sbrian  {NULL, "rm!", IfaceDeleteCommand, LOCAL_AUTH,
72940561Sbrian   "Delete iface address", "iface delete addr", (void *)1},
73040561Sbrian  {NULL, "delete!", IfaceDeleteCommand, LOCAL_AUTH,
73140561Sbrian   "Delete iface address", "iface delete addr", (void *)1},
73240561Sbrian  {"show", NULL, iface_Show, LOCAL_AUTH,
73340561Sbrian   "Show iface address(es)", "iface show"},
73440561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
73550059Sbrian   "Display this message", "nat help|? [command]", IfaceCommands},
73640561Sbrian  {NULL, NULL, NULL},
73740561Sbrian};
73840561Sbrian
73930715Sbrianstatic struct cmdtab const Commands[] = {
74036285Sbrian  {"accept", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
74128679Sbrian  "accept option request", "accept option .."},
74228679Sbrian  {"add", NULL, AddCommand, LOCAL_AUTH,
74332109Sbrian  "add route", "add dest mask gateway", NULL},
74436285Sbrian  {NULL, "add!", AddCommand, LOCAL_AUTH,
74532109Sbrian  "add or change route", "add! dest mask gateway", (void *)1},
74640561Sbrian  {"allow", "auth", RunListCommand, LOCAL_AUTH,
74740561Sbrian  "Allow ppp access", "allow users|modes ....", AllowCommands},
74828679Sbrian  {"bg", "!bg", BgShellCommand, LOCAL_AUTH,
74931372Sbrian  "Run a background command", "[!]bg command"},
75036934Sbrian  {"clear", NULL, ClearCommand, LOCAL_AUTH | LOCAL_CX_OPT,
75146686Sbrian  "Clear throughput statistics",
75281634Sbrian  "clear ipcp|ipv6cp|physical [current|overall|peak]..."},
75336285Sbrian  {"clone", NULL, CloneCommand, LOCAL_AUTH | LOCAL_CX,
75436285Sbrian  "Clone a link", "clone newname..."},
75536285Sbrian  {"close", NULL, CloseCommand, LOCAL_AUTH | LOCAL_CX_OPT,
75636285Sbrian  "Close an FSM", "close [lcp|ccp]"},
75728679Sbrian  {"delete", NULL, DeleteCommand, LOCAL_AUTH,
75832109Sbrian  "delete route", "delete dest", NULL},
75936285Sbrian  {NULL, "delete!", DeleteCommand, LOCAL_AUTH,
76032109Sbrian  "delete a route if it exists", "delete! dest", (void *)1},
76136285Sbrian  {"deny", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
76228679Sbrian  "Deny option request", "deny option .."},
76336285Sbrian  {"dial", "call", DialCommand, LOCAL_AUTH | LOCAL_CX_OPT,
76440797Sbrian  "Dial and login", "dial|call [system ...]", NULL},
76536285Sbrian  {"disable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
76628679Sbrian  "Disable option", "disable option .."},
76736285Sbrian  {"down", NULL, DownCommand, LOCAL_AUTH | LOCAL_CX_OPT,
76846686Sbrian  "Generate a down event", "down [ccp|lcp]"},
76936285Sbrian  {"enable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
77028679Sbrian  "Enable option", "enable option .."},
77163484Sbrian  {"ident", NULL, IdentCommand, LOCAL_AUTH | LOCAL_CX,
77263484Sbrian  "Set the link identity", "ident text..."},
77340561Sbrian  {"iface", "interface", RunListCommand, LOCAL_AUTH,
77440561Sbrian  "interface control", "iface option ...", IfaceCommands},
77536285Sbrian  {"link", "datalink", LinkCommand, LOCAL_AUTH,
77636285Sbrian  "Link specific commands", "link name command ..."},
77737008Sbrian  {"load", NULL, LoadCommand, LOCAL_AUTH | LOCAL_CX_OPT,
77840797Sbrian  "Load settings", "load [system ...]"},
77985991Sbrian  {"log", NULL, LogCommand, LOCAL_AUTH | LOCAL_CX_OPT,
78085991Sbrian  "log information", "log word ..."},
78150059Sbrian#ifndef NONAT
78250059Sbrian  {"nat", "alias", RunListCommand, LOCAL_AUTH,
78358867Sbrian  "NAT control", "nat option yes|no", NatCommands},
78450059Sbrian#endif
78536285Sbrian  {"open", NULL, OpenCommand, LOCAL_AUTH | LOCAL_CX_OPT,
78637955Sbrian  "Open an FSM", "open! [lcp|ccp|ipcp]", (void *)1},
78736285Sbrian  {"passwd", NULL, PasswdCommand, LOCAL_NO_AUTH,
78836285Sbrian  "Password for manipulation", "passwd LocalPassword"},
78936285Sbrian  {"quit", "bye", QuitCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
79036285Sbrian  "Quit PPP program", "quit|bye [all]"},
79136285Sbrian  {"remove", "rm", RemoveCommand, LOCAL_AUTH | LOCAL_CX,
79236285Sbrian  "Remove a link", "remove"},
79336285Sbrian  {"rename", "mv", RenameCommand, LOCAL_AUTH | LOCAL_CX,
79436285Sbrian  "Rename a link", "rename name"},
79558044Sbrian  {"resolv", NULL, ResolvCommand, LOCAL_AUTH,
79658044Sbrian  "Manipulate resolv.conf", "resolv readonly|reload|restore|rewrite|writable"},
79728679Sbrian  {"save", NULL, SaveCommand, LOCAL_AUTH,
79828679Sbrian  "Save settings", "save"},
79963484Sbrian  {"sendident", NULL, SendIdentification, LOCAL_AUTH | LOCAL_CX,
80063484Sbrian  "Transmit the link identity", "sendident"},
80136285Sbrian  {"set", "setup", SetCommand, LOCAL_AUTH | LOCAL_CX_OPT,
80228679Sbrian  "Set parameters", "set[up] var value"},
80328679Sbrian  {"shell", "!", FgShellCommand, LOCAL_AUTH,
80428679Sbrian  "Run a subshell", "shell|! [sh command]"},
80536285Sbrian  {"show", NULL, ShowCommand, LOCAL_AUTH | LOCAL_CX_OPT,
80631372Sbrian  "Show status and stats", "show var"},
80736285Sbrian  {"term", NULL, TerminalCommand, LOCAL_AUTH | LOCAL_CX,
80831372Sbrian  "Enter terminal mode", "term"},
80928679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
81031343Sbrian  "Display this message", "help|? [command]", Commands},
81128679Sbrian  {NULL, NULL, NULL},
8126059Samurai};
8136059Samurai
81428536Sbrianstatic int
81531343SbrianShowEscape(struct cmdargs const *arg)
8166059Samurai{
81736285Sbrian  if (arg->cx->physical->async.cfg.EscMap[32]) {
81836285Sbrian    int code, bit;
81936285Sbrian    const char *sep = "";
8206059Samurai
82126516Sbrian    for (code = 0; code < 32; code++)
82236285Sbrian      if (arg->cx->physical->async.cfg.EscMap[code])
82328679Sbrian	for (bit = 0; bit < 8; bit++)
82436285Sbrian	  if (arg->cx->physical->async.cfg.EscMap[code] & (1 << bit)) {
82536285Sbrian	    prompt_Printf(arg->prompt, "%s0x%02x", sep, (code << 3) + bit);
82636285Sbrian            sep = ", ";
82736285Sbrian          }
82836285Sbrian    prompt_Printf(arg->prompt, "\n");
8296059Samurai  }
83031077Sbrian  return 0;
8316059Samurai}
8326059Samurai
83328679Sbrianstatic int
83436285SbrianShowTimerList(struct cmdargs const *arg)
8356059Samurai{
83636285Sbrian  timer_Show(0, arg->prompt);
83731077Sbrian  return 0;
8386059Samurai}
8396059Samurai
84028679Sbrianstatic int
84131343SbrianShowStopped(struct cmdargs const *arg)
84228327Sbrian{
84336285Sbrian  prompt_Printf(arg->prompt, " Stopped Timer:  LCP: ");
84436285Sbrian  if (!arg->cx->physical->link.lcp.fsm.StoppedTimer.load)
84536285Sbrian    prompt_Printf(arg->prompt, "Disabled");
84628327Sbrian  else
84736285Sbrian    prompt_Printf(arg->prompt, "%ld secs",
84836285Sbrian                  arg->cx->physical->link.lcp.fsm.StoppedTimer.load / SECTICKS);
84928461Sbrian
85036285Sbrian  prompt_Printf(arg->prompt, ", CCP: ");
85136285Sbrian  if (!arg->cx->physical->link.ccp.fsm.StoppedTimer.load)
85236285Sbrian    prompt_Printf(arg->prompt, "Disabled");
85328461Sbrian  else
85436285Sbrian    prompt_Printf(arg->prompt, "%ld secs",
85536285Sbrian                  arg->cx->physical->link.ccp.fsm.StoppedTimer.load / SECTICKS);
85628461Sbrian
85736285Sbrian  prompt_Printf(arg->prompt, "\n");
85828461Sbrian
85931077Sbrian  return 0;
86028327Sbrian}
86128327Sbrian
86228679Sbrianstatic int
86331343SbrianShowVersion(struct cmdargs const *arg)
8646059Samurai{
86551026Sbrian  prompt_Printf(arg->prompt, "PPP Version %s - %s\n", Version, __DATE__);
86631077Sbrian  return 0;
8676059Samurai}
8686059Samurai
86928679Sbrianstatic int
87036285SbrianShowProtocolStats(struct cmdargs const *arg)
87126326Sbrian{
87236285Sbrian  struct link *l = command_ChooseLink(arg);
87326326Sbrian
87436285Sbrian  prompt_Printf(arg->prompt, "%s:\n", l->name);
87536285Sbrian  link_ReportProtocolStatus(l, arg->prompt);
87631077Sbrian  return 0;
87726326Sbrian}
87826326Sbrian
87930715Sbrianstatic struct cmdtab const ShowCommands[] = {
88036285Sbrian  {"bundle", NULL, bundle_ShowStatus, LOCAL_AUTH,
88136285Sbrian  "bundle details", "show bundle"},
88236285Sbrian  {"ccp", NULL, ccp_ReportStatus, LOCAL_AUTH | LOCAL_CX_OPT,
88336285Sbrian  "CCP status", "show cpp"},
88436285Sbrian  {"compress", NULL, sl_Show, LOCAL_AUTH,
88536285Sbrian  "VJ compression stats", "show compress"},
88636285Sbrian  {"escape", NULL, ShowEscape, LOCAL_AUTH | LOCAL_CX,
88736285Sbrian  "escape characters", "show escape"},
88836285Sbrian  {"filter", NULL, filter_Show, LOCAL_AUTH,
88936285Sbrian  "packet filters", "show filter [in|out|dial|alive]"},
89036285Sbrian  {"hdlc", NULL, hdlc_ReportStatus, LOCAL_AUTH | LOCAL_CX,
89136285Sbrian  "HDLC errors", "show hdlc"},
89240561Sbrian  {"iface", "interface", iface_Show, LOCAL_AUTH,
89340561Sbrian  "Interface status", "show iface"},
89436285Sbrian  {"ipcp", NULL, ipcp_Show, LOCAL_AUTH,
89536285Sbrian  "IPCP status", "show ipcp"},
89681634Sbrian#ifndef NOINET6
89781634Sbrian  {"ipv6cp", NULL, ipv6cp_Show, LOCAL_AUTH,
89881634Sbrian  "IPV6CP status", "show ipv6cp"},
89981634Sbrian#endif
90047211Sbrian  {"layers", NULL, link_ShowLayers, LOCAL_AUTH | LOCAL_CX_OPT,
90147211Sbrian  "Protocol layers", "show layers"},
90236285Sbrian  {"lcp", NULL, lcp_ReportStatus, LOCAL_AUTH | LOCAL_CX,
90336285Sbrian  "LCP status", "show lcp"},
90436285Sbrian  {"link", "datalink", datalink_Show, LOCAL_AUTH | LOCAL_CX,
90536285Sbrian  "(high-level) link info", "show link"},
90636285Sbrian  {"links", NULL, bundle_ShowLinks, LOCAL_AUTH,
90736285Sbrian  "available link names", "show links"},
90836285Sbrian  {"log", NULL, log_ShowLevel, LOCAL_AUTH,
90936285Sbrian  "log levels", "show log"},
91036285Sbrian  {"mem", NULL, mbuf_Show, LOCAL_AUTH,
91136285Sbrian  "mbuf allocations", "show mem"},
91281634Sbrian  {"ncp", NULL, ncp_Show, LOCAL_AUTH,
91381634Sbrian  "NCP status", "show ncp"},
91446686Sbrian  {"physical", NULL, physical_ShowStatus, LOCAL_AUTH | LOCAL_CX,
91546686Sbrian  "(low-level) link info", "show physical"},
91636285Sbrian  {"mp", "multilink", mp_ShowStatus, LOCAL_AUTH,
91736285Sbrian  "multilink setup", "show mp"},
91836285Sbrian  {"proto", NULL, ShowProtocolStats, LOCAL_AUTH | LOCAL_CX_OPT,
91936285Sbrian  "protocol summary", "show proto"},
92036285Sbrian  {"route", NULL, route_Show, LOCAL_AUTH,
92136285Sbrian  "routing table", "show route"},
92236285Sbrian  {"stopped", NULL, ShowStopped, LOCAL_AUTH | LOCAL_CX,
92336285Sbrian  "STOPPED timeout", "show stopped"},
92436285Sbrian  {"timers", NULL, ShowTimerList, LOCAL_AUTH,
92536285Sbrian  "alarm timers", "show timers"},
92628679Sbrian  {"version", NULL, ShowVersion, LOCAL_NO_AUTH | LOCAL_AUTH,
92736285Sbrian  "version string", "show version"},
92836285Sbrian  {"who", NULL, log_ShowWho, LOCAL_AUTH,
92936285Sbrian  "client list", "show who"},
93028679Sbrian  {"help", "?", HelpCommand, LOCAL_NO_AUTH | LOCAL_AUTH,
93131343Sbrian  "Display this message", "show help|? [command]", ShowCommands},
93228679Sbrian  {NULL, NULL, NULL},
9336059Samurai};
9346059Samurai
93530715Sbrianstatic struct cmdtab const *
93631343SbrianFindCommand(struct cmdtab const *cmds, const char *str, int *pmatch)
9376059Samurai{
93826516Sbrian  int nmatch;
93926516Sbrian  int len;
94028679Sbrian  struct cmdtab const *found;
9416059Samurai
94226516Sbrian  found = NULL;
94326516Sbrian  len = strlen(str);
94426516Sbrian  nmatch = 0;
9456059Samurai  while (cmds->func) {
94625566Sbrian    if (cmds->name && strncasecmp(str, cmds->name, len) == 0) {
94726516Sbrian      if (cmds->name[len] == '\0') {
94828679Sbrian	*pmatch = 1;
94928679Sbrian	return cmds;
95026516Sbrian      }
9516059Samurai      nmatch++;
9526059Samurai      found = cmds;
95328679Sbrian    } else if (cmds->alias && strncasecmp(str, cmds->alias, len) == 0) {
95426516Sbrian      if (cmds->alias[len] == '\0') {
95528679Sbrian	*pmatch = 1;
95628679Sbrian	return cmds;
95726516Sbrian      }
9586059Samurai      nmatch++;
9596059Samurai      found = cmds;
9606059Samurai    }
9616059Samurai    cmds++;
9626059Samurai  }
9636059Samurai  *pmatch = nmatch;
96426516Sbrian  return found;
9656059Samurai}
9666059Samurai
96736285Sbrianstatic const char *
96836285SbrianmkPrefix(int argc, char const *const *argv, char *tgt, int sz)
96936285Sbrian{
97036285Sbrian  int f, tlen, len;
97136285Sbrian
97236285Sbrian  tlen = 0;
97336285Sbrian  for (f = 0; f < argc && tlen < sz - 2; f++) {
97436285Sbrian    if (f)
97536285Sbrian      tgt[tlen++] = ' ';
97636285Sbrian    len = strlen(argv[f]);
97736285Sbrian    if (len > sz - tlen - 1)
97836285Sbrian      len = sz - tlen - 1;
97936285Sbrian    strncpy(tgt+tlen, argv[f], len);
98036285Sbrian    tlen += len;
98136285Sbrian  }
98236285Sbrian  tgt[tlen] = '\0';
98336285Sbrian  return tgt;
98436285Sbrian}
98536285Sbrian
98630715Sbrianstatic int
98736285SbrianFindExec(struct bundle *bundle, struct cmdtab const *cmds, int argc, int argn,
98836285Sbrian         char const *const *argv, struct prompt *prompt, struct datalink *cx)
9896059Samurai{
99028679Sbrian  struct cmdtab const *cmd;
9916059Samurai  int val = 1;
9926059Samurai  int nmatch;
99331343Sbrian  struct cmdargs arg;
99436285Sbrian  char prefix[100];
9956059Samurai
99636285Sbrian  cmd = FindCommand(cmds, argv[argn], &nmatch);
9976059Samurai  if (nmatch > 1)
99836285Sbrian    log_Printf(LogWARN, "%s: Ambiguous command\n",
99936285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix));
100036285Sbrian  else if (cmd && (!prompt || (cmd->lauth & prompt->auth))) {
100136285Sbrian    if ((cmd->lauth & LOCAL_CX) && !cx)
100236285Sbrian      /* We've got no context, but we require it */
100336285Sbrian      cx = bundle2datalink(bundle, NULL);
100436285Sbrian
100536285Sbrian    if ((cmd->lauth & LOCAL_CX) && !cx)
100636285Sbrian      log_Printf(LogWARN, "%s: No context (use the `link' command)\n",
100736285Sbrian                mkPrefix(argn+1, argv, prefix, sizeof prefix));
100836285Sbrian    else {
100936285Sbrian      if (cx && !(cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
101036285Sbrian        log_Printf(LogWARN, "%s: Redundant context (%s) ignored\n",
101136285Sbrian                  mkPrefix(argn+1, argv, prefix, sizeof prefix), cx->name);
101236285Sbrian        cx = NULL;
101336285Sbrian      }
101436285Sbrian      arg.cmdtab = cmds;
101536285Sbrian      arg.cmd = cmd;
101636285Sbrian      arg.argc = argc;
101736285Sbrian      arg.argn = argn+1;
101836285Sbrian      arg.argv = argv;
101936285Sbrian      arg.bundle = bundle;
102036285Sbrian      arg.cx = cx;
102136285Sbrian      arg.prompt = prompt;
102236285Sbrian      val = (*cmd->func) (&arg);
102336285Sbrian    }
102431343Sbrian  } else
102536285Sbrian    log_Printf(LogWARN, "%s: Invalid command\n",
102636285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix));
102726516Sbrian
102826516Sbrian  if (val == -1)
102936285Sbrian    log_Printf(LogWARN, "Usage: %s\n", cmd->syntax);
103028679Sbrian  else if (val)
103136285Sbrian    log_Printf(LogWARN, "%s: Failed %d\n",
103236285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix), val);
103326516Sbrian
103426516Sbrian  return val;
10356059Samurai}
10366059Samurai
103737009Sbrianint
103858045Sbriancommand_Expand_Interpret(char *buff, int nb, char *argv[MAXARGS], int offset)
103958045Sbrian{
104058045Sbrian  char buff2[LINE_LEN-offset];
104158045Sbrian
104258045Sbrian  InterpretArg(buff, buff2);
104358045Sbrian  strncpy(buff, buff2, LINE_LEN - offset - 1);
104458045Sbrian  buff[LINE_LEN - offset - 1] = '\0';
104558045Sbrian
104658045Sbrian  return command_Interpret(buff, nb, argv);
104758045Sbrian}
104858045Sbrian
104958045Sbrianint
105037009Sbriancommand_Interpret(char *buff, int nb, char *argv[MAXARGS])
10516059Samurai{
10526059Samurai  char *cp;
10536059Samurai
10546059Samurai  if (nb > 0) {
10556059Samurai    cp = buff + strcspn(buff, "\r\n");
10566059Samurai    if (cp)
10576059Samurai      *cp = '\0';
105855145Sbrian    return MakeArgs(buff, argv, MAXARGS, PARSE_REDUCE);
105937009Sbrian  }
106037009Sbrian  return 0;
106131121Sbrian}
10626059Samurai
106331822Sbrianstatic int
106431822Sbrianarghidden(int argc, char const *const *argv, int n)
106531822Sbrian{
106631822Sbrian  /* Is arg n of the given command to be hidden from the log ? */
106731828Sbrian
106831828Sbrian  /* set authkey xxxxx */
106931828Sbrian  /* set key xxxxx */
107031822Sbrian  if (n == 2 && !strncasecmp(argv[0], "se", 2) &&
107131822Sbrian      (!strncasecmp(argv[1], "authk", 5) || !strncasecmp(argv[1], "ke", 2)))
107231822Sbrian    return 1;
107331822Sbrian
107431828Sbrian  /* passwd xxxxx */
107531828Sbrian  if (n == 1 && !strncasecmp(argv[0], "p", 1))
107631828Sbrian    return 1;
107731828Sbrian
107836285Sbrian  /* set server port xxxxx .... */
107936285Sbrian  if (n == 3 && !strncasecmp(argv[0], "se", 2) &&
108036285Sbrian      !strncasecmp(argv[1], "se", 2))
108136285Sbrian    return 1;
108236285Sbrian
108331822Sbrian  return 0;
108431822Sbrian}
108531822Sbrian
108631121Sbrianvoid
108736285Sbriancommand_Run(struct bundle *bundle, int argc, char const *const *argv,
108837008Sbrian           struct prompt *prompt, const char *label, struct datalink *cx)
108931121Sbrian{
109031156Sbrian  if (argc > 0) {
109136285Sbrian    if (log_IsKept(LogCOMMAND)) {
109247844Sbrian      char buf[LINE_LEN];
109331156Sbrian      int f, n;
109431156Sbrian
109531156Sbrian      if (label) {
109631962Sbrian        strncpy(buf, label, sizeof buf - 3);
109731962Sbrian        buf[sizeof buf - 3] = '\0';
109831156Sbrian        strcat(buf, ": ");
109947844Sbrian        n = strlen(buf);
110047844Sbrian      } else {
110147844Sbrian        *buf = '\0';
110247844Sbrian        n = 0;
110331156Sbrian      }
110447844Sbrian      buf[sizeof buf - 1] = '\0';	/* In case we run out of room in buf */
110547844Sbrian
110631156Sbrian      for (f = 0; f < argc; f++) {
110731962Sbrian        if (n < sizeof buf - 1 && f)
110831156Sbrian          buf[n++] = ' ';
110931822Sbrian        if (arghidden(argc, argv, f))
111036285Sbrian          strncpy(buf+n, "********", sizeof buf - n - 1);
111131822Sbrian        else
111231962Sbrian          strncpy(buf+n, argv[f], sizeof buf - n - 1);
111331156Sbrian        n += strlen(buf+n);
111431156Sbrian      }
111536285Sbrian      log_Printf(LogCOMMAND, "%s\n", buf);
111631156Sbrian    }
111737008Sbrian    FindExec(bundle, Commands, argc, 0, argv, prompt, cx);
111831156Sbrian  }
11196059Samurai}
11206059Samurai
112154914Sbrianint
112236285Sbriancommand_Decode(struct bundle *bundle, char *buff, int nb, struct prompt *prompt,
112336285Sbrian              const char *label)
112431121Sbrian{
112531121Sbrian  int argc;
112637009Sbrian  char *argv[MAXARGS];
112731121Sbrian
112858045Sbrian  if ((argc = command_Expand_Interpret(buff, nb, argv, 0)) < 0)
112954914Sbrian    return 0;
113054914Sbrian
113137008Sbrian  command_Run(bundle, argc, (char const *const *)argv, prompt, label, NULL);
113254914Sbrian  return 1;
113331121Sbrian}
113431121Sbrian
11356059Samuraistatic int
113631343SbrianShowCommand(struct cmdargs const *arg)
11376059Samurai{
113836285Sbrian  if (!arg->prompt)
113936285Sbrian    log_Printf(LogWARN, "show: Cannot show without a prompt\n");
114036285Sbrian  else if (arg->argc > arg->argn)
114136285Sbrian    FindExec(arg->bundle, ShowCommands, arg->argc, arg->argn, arg->argv,
114236285Sbrian             arg->prompt, arg->cx);
11436059Samurai  else
114436285Sbrian    prompt_Printf(arg->prompt, "Use ``show ?'' to get a list.\n");
114526516Sbrian
114626516Sbrian  return 0;
11476059Samurai}
11486059Samurai
11496059Samuraistatic int
115031343SbrianTerminalCommand(struct cmdargs const *arg)
11516059Samurai{
115236285Sbrian  if (!arg->prompt) {
115336285Sbrian    log_Printf(LogWARN, "term: Need a prompt\n");
115426516Sbrian    return 1;
11556059Samurai  }
115636285Sbrian
115736285Sbrian  if (arg->cx->physical->link.lcp.fsm.state > ST_CLOSED) {
115836285Sbrian    prompt_Printf(arg->prompt, "LCP state is [%s]\n",
115936285Sbrian                  State2Nam(arg->cx->physical->link.lcp.fsm.state));
116036285Sbrian    return 1;
11616059Samurai  }
116236285Sbrian
116336285Sbrian  datalink_Up(arg->cx, 0, 0);
116436285Sbrian  prompt_TtyTermMode(arg->prompt, arg->cx);
116536285Sbrian  return 0;
11666059Samurai}
11676059Samurai
11686059Samuraistatic int
116931343SbrianQuitCommand(struct cmdargs const *arg)
11706059Samurai{
117136285Sbrian  if (!arg->prompt || prompt_IsController(arg->prompt) ||
117236285Sbrian      (arg->argc > arg->argn && !strcasecmp(arg->argv[arg->argn], "all") &&
117336285Sbrian       (arg->prompt->auth & LOCAL_AUTH)))
117436285Sbrian    Cleanup(EX_NORMAL);
117536285Sbrian  if (arg->prompt)
117636285Sbrian    prompt_Destroy(arg->prompt, 1);
117726516Sbrian
117826516Sbrian  return 0;
11796059Samurai}
11806059Samurai
11816059Samuraistatic int
118236285SbrianOpenCommand(struct cmdargs const *arg)
11836059Samurai{
118437160Sbrian  if (arg->argc == arg->argn)
118537993Sbrian    bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1);
118637160Sbrian  else if (arg->argc == arg->argn + 1) {
118737160Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp")) {
118837385Sbrian      struct datalink *cx = arg->cx ?
118937385Sbrian        arg->cx : bundle2datalink(arg->bundle, NULL);
119037385Sbrian      if (cx) {
119137385Sbrian        if (cx->physical->link.lcp.fsm.state == ST_OPENED)
119237385Sbrian          fsm_Reopen(&cx->physical->link.lcp.fsm);
119337160Sbrian        else
119437993Sbrian          bundle_Open(arg->bundle, cx->name, PHYS_ALL, 1);
119537160Sbrian      } else
119637160Sbrian        log_Printf(LogWARN, "open lcp: You must specify a link\n");
119737160Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) {
119837160Sbrian      struct fsm *fp;
11996059Samurai
120037210Sbrian      fp = &command_ChooseLink(arg)->ccp.fsm;
120137160Sbrian      if (fp->link->lcp.fsm.state != ST_OPENED)
120237160Sbrian        log_Printf(LogWARN, "open: LCP must be open before opening CCP\n");
120337160Sbrian      else if (fp->state == ST_OPENED)
120437160Sbrian        fsm_Reopen(fp);
120537160Sbrian      else {
120637160Sbrian        fp->open_mode = 0;	/* Not passive any more */
120737160Sbrian        if (fp->state == ST_STOPPED) {
120837160Sbrian          fsm_Down(fp);
120937160Sbrian          fsm_Up(fp);
121037160Sbrian        } else {
121137160Sbrian          fsm_Up(fp);
121237160Sbrian          fsm_Open(fp);
121337160Sbrian        }
121436285Sbrian      }
121537160Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ipcp")) {
121637160Sbrian      if (arg->cx)
121737160Sbrian        log_Printf(LogWARN, "open ipcp: You need not specify a link\n");
121837160Sbrian      if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED)
121937160Sbrian        fsm_Reopen(&arg->bundle->ncp.ipcp.fsm);
122037160Sbrian      else
122137993Sbrian        bundle_Open(arg->bundle, NULL, PHYS_ALL, 1);
122237160Sbrian    } else
122337160Sbrian      return -1;
122436285Sbrian  } else
122536285Sbrian    return -1;
122636285Sbrian
122726516Sbrian  return 0;
12286059Samurai}
12296059Samurai
123025067Sbrianstatic int
123136285SbrianCloseCommand(struct cmdargs const *arg)
12326059Samurai{
123337007Sbrian  if (arg->argc == arg->argn)
123437007Sbrian    bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_STAYDOWN);
123537007Sbrian  else if (arg->argc == arg->argn + 1) {
123637007Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp"))
123737007Sbrian      bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_LCP);
123837007Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "ccp") ||
123937007Sbrian             !strcasecmp(arg->argv[arg->argn], "ccp!")) {
124037007Sbrian      struct fsm *fp;
12416059Samurai
124237210Sbrian      fp = &command_ChooseLink(arg)->ccp.fsm;
124337007Sbrian      if (fp->state == ST_OPENED) {
124437007Sbrian        fsm_Close(fp);
124537007Sbrian        if (arg->argv[arg->argn][3] == '!')
124637007Sbrian          fp->open_mode = 0;		/* Stay ST_CLOSED */
124737007Sbrian        else
124837007Sbrian          fp->open_mode = OPEN_PASSIVE;	/* Wait for the peer to start */
124937007Sbrian      }
125037007Sbrian    } else
125136285Sbrian      return -1;
125236285Sbrian  } else
125336285Sbrian    return -1;
125436285Sbrian
125536285Sbrian  return 0;
12566059Samurai}
12576059Samurai
125825067Sbrianstatic int
125936285SbrianDownCommand(struct cmdargs const *arg)
126011336Samurai{
126137018Sbrian  if (arg->argc == arg->argn) {
126237018Sbrian      if (arg->cx)
126337018Sbrian        datalink_Down(arg->cx, CLOSE_STAYDOWN);
126437018Sbrian      else
126537018Sbrian        bundle_Down(arg->bundle, CLOSE_STAYDOWN);
126637018Sbrian  } else if (arg->argc == arg->argn + 1) {
126737018Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp")) {
126837018Sbrian      if (arg->cx)
126937018Sbrian        datalink_Down(arg->cx, CLOSE_LCP);
127037018Sbrian      else
127137018Sbrian        bundle_Down(arg->bundle, CLOSE_LCP);
127237018Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) {
127337018Sbrian      struct fsm *fp = arg->cx ? &arg->cx->physical->link.ccp.fsm :
127437018Sbrian                                 &arg->bundle->ncp.mp.link.ccp.fsm;
127537060Sbrian      fsm2initial(fp);
127637018Sbrian    } else
127737018Sbrian      return -1;
127836285Sbrian  } else
127936285Sbrian    return -1;
128036285Sbrian
128136285Sbrian  return 0;
128225067Sbrian}
128325067Sbrian
128425067Sbrianstatic int
128536285SbrianSetModemSpeed(struct cmdargs const *arg)
128625067Sbrian{
128736285Sbrian  long speed;
128836285Sbrian  char *end;
128911336Samurai
129036285Sbrian  if (arg->argc > arg->argn && *arg->argv[arg->argn]) {
129136285Sbrian    if (arg->argc > arg->argn+1) {
129254917Sbrian      log_Printf(LogWARN, "SetModemSpeed: Too many arguments\n");
129336285Sbrian      return -1;
129411336Samurai    }
129536285Sbrian    if (strcasecmp(arg->argv[arg->argn], "sync") == 0) {
129636285Sbrian      physical_SetSync(arg->cx->physical);
129736285Sbrian      return 0;
129836285Sbrian    }
129936285Sbrian    end = NULL;
130036285Sbrian    speed = strtol(arg->argv[arg->argn], &end, 10);
130136285Sbrian    if (*end) {
130236285Sbrian      log_Printf(LogWARN, "SetModemSpeed: Bad argument \"%s\"",
130336285Sbrian                arg->argv[arg->argn]);
130436285Sbrian      return -1;
130536285Sbrian    }
130636285Sbrian    if (physical_SetSpeed(arg->cx->physical, speed))
130736285Sbrian      return 0;
130836285Sbrian    log_Printf(LogWARN, "%s: Invalid speed\n", arg->argv[arg->argn]);
130936285Sbrian  } else
131036285Sbrian    log_Printf(LogWARN, "SetModemSpeed: No speed specified\n");
131124939Sbrian
131226516Sbrian  return -1;
131311336Samurai}
131411336Samurai
131525067Sbrianstatic int
131631343SbrianSetStoppedTimeout(struct cmdargs const *arg)
131728327Sbrian{
131836285Sbrian  struct link *l = &arg->cx->physical->link;
131936285Sbrian
132036285Sbrian  l->lcp.fsm.StoppedTimer.load = 0;
132136285Sbrian  l->ccp.fsm.StoppedTimer.load = 0;
132236285Sbrian  if (arg->argc <= arg->argn+2) {
132336285Sbrian    if (arg->argc > arg->argn) {
132436285Sbrian      l->lcp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn]) * SECTICKS;
132536285Sbrian      if (arg->argc > arg->argn+1)
132636285Sbrian        l->ccp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn+1]) * SECTICKS;
132728461Sbrian    }
132828327Sbrian    return 0;
132928327Sbrian  }
133028327Sbrian  return -1;
133128327Sbrian}
133228327Sbrian
133328327Sbrianstatic int
133431343SbrianSetServer(struct cmdargs const *arg)
133526940Sbrian{
133626940Sbrian  int res = -1;
133726940Sbrian
133836285Sbrian  if (arg->argc > arg->argn && arg->argc < arg->argn+4) {
133931081Sbrian    const char *port, *passwd, *mask;
134053125Sbrian    int mlen;
134131081Sbrian
134231081Sbrian    /* What's what ? */
134336285Sbrian    port = arg->argv[arg->argn];
134436285Sbrian    if (arg->argc == arg->argn + 2) {
134536285Sbrian      passwd = arg->argv[arg->argn+1];
134636285Sbrian      mask = NULL;
134736285Sbrian    } else if (arg->argc == arg->argn + 3) {
134836285Sbrian      passwd = arg->argv[arg->argn+1];
134936285Sbrian      mask = arg->argv[arg->argn+2];
135053125Sbrian      mlen = strlen(mask);
135153125Sbrian      if (mlen == 0 || mlen > 4 || strspn(mask, "01234567") != mlen ||
135253125Sbrian          (mlen == 4 && *mask != '0')) {
135353125Sbrian        log_Printf(LogWARN, "%s %s: %s: Invalid mask\n",
135453125Sbrian                   arg->argv[arg->argn - 2], arg->argv[arg->argn - 1], mask);
135531081Sbrian        return -1;
135653125Sbrian      }
135771764Sbrian    } else if (arg->argc != arg->argn + 1)
135871764Sbrian      return -1;
135971764Sbrian    else if (strcasecmp(port, "none") == 0) {
136071657Sbrian      if (server_Clear(arg->bundle))
136171657Sbrian        log_Printf(LogPHASE, "Disabled server socket\n");
136271657Sbrian      return 0;
136371657Sbrian    } else if (strcasecmp(port, "open") == 0) {
136471657Sbrian      switch (server_Reopen(arg->bundle)) {
136571657Sbrian        case SERVER_OK:
136671657Sbrian          return 0;
136771657Sbrian        case SERVER_FAILED:
136871764Sbrian          log_Printf(LogWARN, "Failed to reopen server port\n");
136971657Sbrian          return 1;
137071657Sbrian        case SERVER_UNSET:
137171764Sbrian          log_Printf(LogWARN, "Cannot reopen unset server socket\n");
137271657Sbrian          return 1;
137371657Sbrian        default:
137471657Sbrian          break;
137571657Sbrian      }
137671657Sbrian      return -1;
137771657Sbrian    } else if (strcasecmp(port, "closed") == 0) {
137836285Sbrian      if (server_Close(arg->bundle))
137971657Sbrian        log_Printf(LogPHASE, "Closed server socket\n");
138071657Sbrian      else
138171657Sbrian        log_Printf(LogWARN, "Server socket not open\n");
138271657Sbrian
138336285Sbrian      return 0;
138431081Sbrian    } else
138536285Sbrian      return -1;
138631081Sbrian
138771657Sbrian    strncpy(server.cfg.passwd, passwd, sizeof server.cfg.passwd - 1);
138871657Sbrian    server.cfg.passwd[sizeof server.cfg.passwd - 1] = '\0';
138931081Sbrian
139036285Sbrian    if (*port == '/') {
139131081Sbrian      mode_t imask;
139236285Sbrian      char *ptr, name[LINE_LEN + 12];
139328679Sbrian
139453125Sbrian      if (mask == NULL)
139531081Sbrian        imask = (mode_t)-1;
139653125Sbrian      else for (imask = mlen = 0; mask[mlen]; mlen++)
139753125Sbrian        imask = (imask * 8) + mask[mlen] - '0';
139836285Sbrian
139936285Sbrian      ptr = strstr(port, "%d");
140036285Sbrian      if (ptr) {
140136285Sbrian        snprintf(name, sizeof name, "%.*s%d%s",
140237210Sbrian                 (int)(ptr - port), port, arg->bundle->unit, ptr + 2);
140336285Sbrian        port = name;
140436285Sbrian      }
140536285Sbrian      res = server_LocalOpen(arg->bundle, port, imask);
140627346Sbrian    } else {
140736285Sbrian      int iport, add = 0;
140828679Sbrian
140931081Sbrian      if (mask != NULL)
141031081Sbrian        return -1;
141128679Sbrian
141236285Sbrian      if (*port == '+') {
141336285Sbrian        port++;
141436285Sbrian        add = 1;
141536285Sbrian      }
141631081Sbrian      if (strspn(port, "0123456789") != strlen(port)) {
141731081Sbrian        struct servent *s;
141831081Sbrian
141931081Sbrian        if ((s = getservbyname(port, "tcp")) == NULL) {
142031081Sbrian	  iport = 0;
142136285Sbrian	  log_Printf(LogWARN, "%s: Invalid port or service\n", port);
142228679Sbrian	} else
142331081Sbrian	  iport = ntohs(s->s_port);
142427346Sbrian      } else
142531081Sbrian        iport = atoi(port);
142636285Sbrian
142736285Sbrian      if (iport) {
142836285Sbrian        if (add)
142936285Sbrian          iport += arg->bundle->unit;
143036285Sbrian        res = server_TcpOpen(arg->bundle, iport);
143136285Sbrian      } else
143236285Sbrian        res = -1;
143327346Sbrian    }
143431081Sbrian  }
143526940Sbrian
143626940Sbrian  return res;
143726940Sbrian}
143826940Sbrian
143926940Sbrianstatic int
144031343SbrianSetEscape(struct cmdargs const *arg)
14416059Samurai{
14426059Samurai  int code;
144336285Sbrian  int argc = arg->argc - arg->argn;
144436285Sbrian  char const *const *argv = arg->argv + arg->argn;
14456059Samurai
14466059Samurai  for (code = 0; code < 33; code++)
144736285Sbrian    arg->cx->physical->async.cfg.EscMap[code] = 0;
144831343Sbrian
14496059Samurai  while (argc-- > 0) {
14506059Samurai    sscanf(*argv++, "%x", &code);
14516059Samurai    code &= 0xff;
145236285Sbrian    arg->cx->physical->async.cfg.EscMap[code >> 3] |= (1 << (code & 7));
145336285Sbrian    arg->cx->physical->async.cfg.EscMap[32] = 1;
14546059Samurai  }
145526516Sbrian  return 0;
14566059Samurai}
14576059Samurai
14586059Samuraistatic int
145931343SbrianSetInterfaceAddr(struct cmdargs const *arg)
14606059Samurai{
146181634Sbrian  struct ncp *ncp = &arg->bundle->ncp;
146281634Sbrian  struct ncpaddr ncpaddr;
146332267Sbrian  const char *hisaddr;
146432267Sbrian
146540561Sbrian  if (arg->argc > arg->argn + 4)
146640561Sbrian    return -1;
146740561Sbrian
146832267Sbrian  hisaddr = NULL;
146981634Sbrian  memset(&ncp->ipcp.cfg.my_range, '\0', sizeof ncp->ipcp.cfg.my_range);
147081634Sbrian  memset(&ncp->ipcp.cfg.peer_range, '\0', sizeof ncp->ipcp.cfg.peer_range);
147181634Sbrian  ncp->ipcp.cfg.HaveTriggerAddress = 0;
147281634Sbrian  ncp->ipcp.cfg.netmask.s_addr = INADDR_ANY;
147381634Sbrian  iplist_reset(&ncp->ipcp.cfg.peer_list);
147428394Sbrian
147536285Sbrian  if (arg->argc > arg->argn) {
147681634Sbrian    if (!ncprange_aton(&ncp->ipcp.cfg.my_range, ncp, arg->argv[arg->argn]))
147728679Sbrian      return 1;
147836285Sbrian    if (arg->argc > arg->argn+1) {
147936285Sbrian      hisaddr = arg->argv[arg->argn+1];
148036285Sbrian      if (arg->argc > arg->argn+2) {
148181634Sbrian        ncp->ipcp.ifmask = ncp->ipcp.cfg.netmask =
148281634Sbrian          GetIpAddr(arg->argv[arg->argn+2]);
148336285Sbrian	if (arg->argc > arg->argn+3) {
148481634Sbrian	  ncp->ipcp.cfg.TriggerAddress = GetIpAddr(arg->argv[arg->argn+3]);
148581634Sbrian	  ncp->ipcp.cfg.HaveTriggerAddress = 1;
14869440Samurai	}
14876059Samurai      }
14886059Samurai    }
14896059Samurai  }
149028394Sbrian
149140561Sbrian  /* 0.0.0.0 means any address (0 bits) */
149281634Sbrian  ncpaddr_getip4(&ncpaddr, &ncp->ipcp.my_ip);
149381634Sbrian  ncprange_getaddr(&ncp->ipcp.cfg.my_range, &ncpaddr);
149481634Sbrian  if (ncp->ipcp.my_ip.s_addr == INADDR_ANY)
149581634Sbrian    ncprange_setwidth(&ncp->ipcp.cfg.my_range, 0);
149681634Sbrian  bundle_AdjustFilters(arg->bundle, &ncpaddr, NULL);
149736285Sbrian
149836285Sbrian  if (hisaddr && !ipcp_UseHisaddr(arg->bundle, hisaddr,
149936928Sbrian                                  arg->bundle->phys_type.all & PHYS_AUTO))
150032267Sbrian    return 4;
150131121Sbrian
150226516Sbrian  return 0;
15036059Samurai}
15046059Samurai
150518752Sjkhstatic int
150644305SbrianSetRetry(int argc, char const *const *argv, u_int *timeout, u_int *maxreq,
150744305Sbrian          u_int *maxtrm, int def)
150844305Sbrian{
150944305Sbrian  if (argc == 0) {
151044305Sbrian    *timeout = DEF_FSMRETRY;
151144305Sbrian    *maxreq = def;
151244305Sbrian    if (maxtrm != NULL)
151344305Sbrian      *maxtrm = def;
151444305Sbrian  } else {
151544305Sbrian    long l = atol(argv[0]);
151644305Sbrian
151744305Sbrian    if (l < MIN_FSMRETRY) {
151844305Sbrian      log_Printf(LogWARN, "%ld: Invalid FSM retry period - min %d\n",
151944305Sbrian                 l, MIN_FSMRETRY);
152044305Sbrian      return 1;
152144305Sbrian    } else
152244305Sbrian      *timeout = l;
152344305Sbrian
152444305Sbrian    if (argc > 1) {
152544305Sbrian      l = atol(argv[1]);
152644305Sbrian      if (l < 1) {
152744305Sbrian        log_Printf(LogWARN, "%ld: Invalid FSM REQ tries - changed to 1\n", l);
152844305Sbrian        l = 1;
152944305Sbrian      }
153044305Sbrian      *maxreq = l;
153144305Sbrian
153244305Sbrian      if (argc > 2 && maxtrm != NULL) {
153344305Sbrian        l = atol(argv[2]);
153444305Sbrian        if (l < 1) {
153544305Sbrian          log_Printf(LogWARN, "%ld: Invalid FSM TRM tries - changed to 1\n", l);
153644305Sbrian          l = 1;
153744305Sbrian        }
153844305Sbrian        *maxtrm = l;
153944305Sbrian      }
154044305Sbrian    }
154144305Sbrian  }
154244305Sbrian
154344305Sbrian  return 0;
154444305Sbrian}
154544305Sbrian
154644305Sbrianstatic int
154731343SbrianSetVariable(struct cmdargs const *arg)
15486059Samurai{
154937210Sbrian  long long_val, param = (long)arg->cmd->args;
155079119Sbrian  int mode, dummyint, f, first, res;
155178410Sbrian  u_short *change;
155231343Sbrian  const char *argp;
155336285Sbrian  struct datalink *cx = arg->cx;	/* LOCAL_CX uses this */
155436285Sbrian  struct link *l = command_ChooseLink(arg);	/* LOCAL_CX_OPT uses this */
155581634Sbrian  struct in_addr *ipaddr;
155681634Sbrian  struct ncpaddr ncpaddr[2];
15576059Samurai
155836285Sbrian  if (arg->argc > arg->argn)
155936285Sbrian    argp = arg->argv[arg->argn];
156026551Sbrian  else
156131343Sbrian    argp = "";
156226551Sbrian
156379119Sbrian  res = 0;
156479119Sbrian
156536285Sbrian  if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
156636285Sbrian    log_Printf(LogWARN, "set %s: No context (use the `link' command)\n",
156736285Sbrian              arg->cmd->name);
156836285Sbrian    return 1;
156936285Sbrian  } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
157036285Sbrian    log_Printf(LogWARN, "set %s: Redundant context (%s) ignored\n",
157136285Sbrian              arg->cmd->name, cx->name);
157236285Sbrian    cx = NULL;
157336285Sbrian  }
157436285Sbrian
157526551Sbrian  switch (param) {
157628679Sbrian  case VAR_AUTHKEY:
157750139Sbrian    strncpy(arg->bundle->cfg.auth.key, argp,
157850139Sbrian            sizeof arg->bundle->cfg.auth.key - 1);
157950139Sbrian    arg->bundle->cfg.auth.key[sizeof arg->bundle->cfg.auth.key - 1] = '\0';
158028679Sbrian    break;
158137210Sbrian
158228679Sbrian  case VAR_AUTHNAME:
158340622Sbrian    switch (bundle_Phase(arg->bundle)) {
158458880Sbrian      default:
158558880Sbrian        log_Printf(LogWARN, "Altering authname while at phase %s\n",
158658880Sbrian                   bundle_PhaseName(arg->bundle));
158758880Sbrian        /* drop through */
158840622Sbrian      case PHASE_DEAD:
158940622Sbrian      case PHASE_ESTABLISH:
159040622Sbrian        strncpy(arg->bundle->cfg.auth.name, argp,
159140622Sbrian                sizeof arg->bundle->cfg.auth.name - 1);
159240622Sbrian        arg->bundle->cfg.auth.name[sizeof arg->bundle->cfg.auth.name-1] = '\0';
159340622Sbrian        break;
159436285Sbrian    }
159528679Sbrian    break;
159637210Sbrian
159736285Sbrian  case VAR_AUTOLOAD:
159849434Sbrian    if (arg->argc == arg->argn + 3) {
159949434Sbrian      int v1, v2, v3;
160049434Sbrian      char *end;
160149434Sbrian
160249434Sbrian      v1 = strtol(arg->argv[arg->argn], &end, 0);
160349434Sbrian      if (v1 < 0 || *end) {
160449434Sbrian        log_Printf(LogWARN, "autoload: %s: Invalid min percentage\n",
160549434Sbrian                   arg->argv[arg->argn]);
160679119Sbrian        res = 1;
160779119Sbrian        break;
160836285Sbrian      }
160949434Sbrian
161049434Sbrian      v2 = strtol(arg->argv[arg->argn + 1], &end, 0);
161149434Sbrian      if (v2 < 0 || *end) {
161249434Sbrian        log_Printf(LogWARN, "autoload: %s: Invalid max percentage\n",
161349434Sbrian                   arg->argv[arg->argn + 1]);
161479119Sbrian        res = 1;
161579119Sbrian        break;
161649434Sbrian      }
161749434Sbrian      if (v2 < v1) {
161849434Sbrian        v3 = v1;
161949434Sbrian        v1 = v2;
162049434Sbrian        v2 = v3;
162149434Sbrian      }
162249434Sbrian
162349434Sbrian      v3 = strtol(arg->argv[arg->argn + 2], &end, 0);
162449434Sbrian      if (v3 <= 0 || *end) {
162549434Sbrian        log_Printf(LogWARN, "autoload: %s: Invalid throughput period\n",
162649434Sbrian                   arg->argv[arg->argn + 2]);
162779119Sbrian        res = 1;
162879119Sbrian        break;
162949434Sbrian      }
163049434Sbrian
163149434Sbrian      arg->bundle->ncp.mp.cfg.autoload.min = v1;
163249434Sbrian      arg->bundle->ncp.mp.cfg.autoload.max = v2;
163349434Sbrian      arg->bundle->ncp.mp.cfg.autoload.period = v3;
163449434Sbrian      mp_RestartAutoloadTimer(&arg->bundle->ncp.mp);
163536285Sbrian    } else {
163679119Sbrian      log_Printf(LogWARN, "Set autoload requires three arguments\n");
163779119Sbrian      res = 1;
163836285Sbrian    }
163936285Sbrian    break;
164037210Sbrian
164128679Sbrian  case VAR_DIAL:
164236285Sbrian    strncpy(cx->cfg.script.dial, argp, sizeof cx->cfg.script.dial - 1);
164336285Sbrian    cx->cfg.script.dial[sizeof cx->cfg.script.dial - 1] = '\0';
164428679Sbrian    break;
164537210Sbrian
164628679Sbrian  case VAR_LOGIN:
164736285Sbrian    strncpy(cx->cfg.script.login, argp, sizeof cx->cfg.script.login - 1);
164836285Sbrian    cx->cfg.script.login[sizeof cx->cfg.script.login - 1] = '\0';
164928679Sbrian    break;
165037210Sbrian
165136285Sbrian  case VAR_WINSIZE:
165236285Sbrian    if (arg->argc > arg->argn) {
165336285Sbrian      l->ccp.cfg.deflate.out.winsize = atoi(arg->argv[arg->argn]);
165436285Sbrian      if (l->ccp.cfg.deflate.out.winsize < 8 ||
165536285Sbrian          l->ccp.cfg.deflate.out.winsize > 15) {
165636285Sbrian          log_Printf(LogWARN, "%d: Invalid outgoing window size\n",
165736285Sbrian                    l->ccp.cfg.deflate.out.winsize);
165836285Sbrian          l->ccp.cfg.deflate.out.winsize = 15;
165936285Sbrian      }
166036285Sbrian      if (arg->argc > arg->argn+1) {
166136285Sbrian        l->ccp.cfg.deflate.in.winsize = atoi(arg->argv[arg->argn+1]);
166236285Sbrian        if (l->ccp.cfg.deflate.in.winsize < 8 ||
166336285Sbrian            l->ccp.cfg.deflate.in.winsize > 15) {
166436285Sbrian            log_Printf(LogWARN, "%d: Invalid incoming window size\n",
166536285Sbrian                      l->ccp.cfg.deflate.in.winsize);
166636285Sbrian            l->ccp.cfg.deflate.in.winsize = 15;
166736285Sbrian        }
166836285Sbrian      } else
166936285Sbrian        l->ccp.cfg.deflate.in.winsize = 0;
167036285Sbrian    } else {
167179119Sbrian      log_Printf(LogWARN, "No window size specified\n");
167279119Sbrian      res = 1;
167336285Sbrian    }
167436285Sbrian    break;
167537210Sbrian
167667910Sbrian#ifdef HAVE_DES
167778411Sbrian  case VAR_MPPE:
167879119Sbrian    if (arg->argc > arg->argn + 2) {
167979119Sbrian      res = -1;
168079119Sbrian      break;
168179119Sbrian    }
168278411Sbrian
168378411Sbrian    if (arg->argc == arg->argn) {
168478411Sbrian      l->ccp.cfg.mppe.keybits = 0;
168578411Sbrian      l->ccp.cfg.mppe.state = MPPE_ANYSTATE;
168678411Sbrian      l->ccp.cfg.mppe.required = 0;
168778411Sbrian      break;
168878411Sbrian    }
168978411Sbrian
169078411Sbrian    if (!strcmp(argp, "*"))
169178411Sbrian      long_val = 0;
169278411Sbrian    else {
169378411Sbrian      long_val = atol(argp);
169478411Sbrian      if (long_val != 40 && long_val != 56 && long_val != 128) {
169578411Sbrian        log_Printf(LogWARN, "%s: Invalid bits value\n", argp);
169679119Sbrian        res = -1;
169779119Sbrian        break;
169867910Sbrian      }
169967910Sbrian    }
170078411Sbrian
170178411Sbrian    if (arg->argc == arg->argn + 2) {
170278411Sbrian      if (!strcmp(arg->argv[arg->argn + 1], "*"))
170378411Sbrian        l->ccp.cfg.mppe.state = MPPE_ANYSTATE;
170478411Sbrian      else if (!strcasecmp(arg->argv[arg->argn + 1], "stateless"))
170578411Sbrian        l->ccp.cfg.mppe.state = MPPE_STATELESS;
170679370Sbrian      else if (!strcasecmp(arg->argv[arg->argn + 1], "stateful"))
170778411Sbrian        l->ccp.cfg.mppe.state = MPPE_STATEFUL;
170878411Sbrian      else {
170978411Sbrian        log_Printf(LogWARN, "%s: Invalid state value\n",
171078411Sbrian                   arg->argv[arg->argn + 1]);
171179119Sbrian        res = -1;
171279119Sbrian        break;
171378411Sbrian      }
171478411Sbrian    } else
171578411Sbrian      l->ccp.cfg.mppe.state = MPPE_ANYSTATE;
171678411Sbrian    l->ccp.cfg.mppe.keybits = long_val;
171778411Sbrian    l->ccp.cfg.mppe.required = 1;
171867910Sbrian    break;
171967910Sbrian#endif
172067910Sbrian
172128679Sbrian  case VAR_DEVICE:
172236285Sbrian    physical_SetDeviceList(cx->physical, arg->argc - arg->argn,
172336285Sbrian                           arg->argv + arg->argn);
172436285Sbrian    break;
172537210Sbrian
172636285Sbrian  case VAR_ACCMAP:
172736285Sbrian    if (arg->argc > arg->argn) {
172837210Sbrian      u_long ulong_val;
172936285Sbrian      sscanf(argp, "%lx", &ulong_val);
173037210Sbrian      cx->physical->link.lcp.cfg.accmap = (u_int32_t)ulong_val;
173136285Sbrian    } else {
173279119Sbrian      log_Printf(LogWARN, "No accmap specified\n");
173379119Sbrian      res = 1;
173436285Sbrian    }
173536285Sbrian    break;
173637210Sbrian
173736285Sbrian  case VAR_MODE:
173836285Sbrian    mode = Nam2mode(argp);
173936285Sbrian    if (mode == PHYS_NONE || mode == PHYS_ALL) {
174036285Sbrian      log_Printf(LogWARN, "%s: Invalid mode\n", argp);
174179119Sbrian      res = -1;
174279119Sbrian      break;
174336285Sbrian    }
174436285Sbrian    bundle_SetMode(arg->bundle, cx, mode);
174536285Sbrian    break;
174637210Sbrian
174736285Sbrian  case VAR_MRRU:
174840622Sbrian    switch (bundle_Phase(arg->bundle)) {
174940622Sbrian      case PHASE_DEAD:
175040622Sbrian        break;
175140622Sbrian      case PHASE_ESTABLISH:
175240622Sbrian        /* Make sure none of our links are DATALINK_LCP or greater */
175340622Sbrian        if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) {
175440622Sbrian          log_Printf(LogWARN, "mrru: Only changable before LCP negotiations\n");
175579119Sbrian          res = 1;
175679119Sbrian          break;
175740622Sbrian        }
175840622Sbrian        break;
175940622Sbrian      default:
176040622Sbrian        log_Printf(LogWARN, "mrru: Only changable at phase DEAD/ESTABLISH\n");
176179119Sbrian        res = 1;
176279119Sbrian        break;
176329696Sbrian    }
176479119Sbrian    if (res != 0)
176579119Sbrian      break;
176637210Sbrian    long_val = atol(argp);
176737210Sbrian    if (long_val && long_val < MIN_MRU) {
176837210Sbrian      log_Printf(LogWARN, "MRRU %ld: too small - min %d\n", long_val, MIN_MRU);
176979119Sbrian      res = 1;
177079119Sbrian      break;
177137210Sbrian    } else if (long_val > MAX_MRU) {
177237210Sbrian      log_Printf(LogWARN, "MRRU %ld: too big - max %d\n", long_val, MAX_MRU);
177379119Sbrian      res = 1;
177479119Sbrian      break;
177537210Sbrian    } else
177637210Sbrian      arg->bundle->ncp.mp.cfg.mrru = long_val;
177728679Sbrian    break;
177837210Sbrian
177936285Sbrian  case VAR_MRU:
178079163Sbrian    long_val = 0;	/* silence gcc */
178179163Sbrian    change = NULL;	/* silence gcc */
178278410Sbrian    switch(arg->argc - arg->argn) {
178378410Sbrian    case 1:
178479119Sbrian      if (argp[strspn(argp, "0123456789")] != '\0') {
178579119Sbrian        res = -1;
178679119Sbrian        break;
178779119Sbrian      }
178879119Sbrian      /*FALLTHRU*/
178978410Sbrian    case 0:
179078410Sbrian      long_val = atol(argp);
179178410Sbrian      change = &l->lcp.cfg.mru;
179278410Sbrian      if (long_val > l->lcp.cfg.max_mru) {
179378410Sbrian        log_Printf(LogWARN, "MRU %ld: too large - max set to %d\n", long_val,
179478410Sbrian                   l->lcp.cfg.max_mru);
179579119Sbrian        res = 1;
179679119Sbrian        break;
179778410Sbrian      }
179878410Sbrian      break;
179978410Sbrian    case 2:
180079119Sbrian      if (strcasecmp(argp, "max") && strcasecmp(argp, "maximum")) {
180179119Sbrian        res = -1;
180279119Sbrian        break;
180379119Sbrian      }
180478410Sbrian      long_val = atol(arg->argv[arg->argn + 1]);
180578410Sbrian      change = &l->lcp.cfg.max_mru;
180678410Sbrian      if (long_val > MAX_MRU) {
180778410Sbrian        log_Printf(LogWARN, "MRU %ld: too large - maximum is %d\n", long_val,
180878410Sbrian                   MAX_MRU);
180979119Sbrian        res = 1;
181079119Sbrian        break;
181178410Sbrian      }
181278410Sbrian      break;
181378410Sbrian    default:
181479119Sbrian      res = -1;
181579119Sbrian      break;
181678410Sbrian    }
181779119Sbrian    if (res != 0)
181879119Sbrian      break;
181978410Sbrian
182037210Sbrian    if (long_val == 0)
182180385Sbrian      *change = 0;
182237210Sbrian    else if (long_val < MIN_MRU) {
182337210Sbrian      log_Printf(LogWARN, "MRU %ld: too small - min %d\n", long_val, MIN_MRU);
182479119Sbrian      res = 1;
182579119Sbrian      break;
182637210Sbrian    } else if (long_val > MAX_MRU) {
182737210Sbrian      log_Printf(LogWARN, "MRU %ld: too big - max %d\n", long_val, MAX_MRU);
182879119Sbrian      res = 1;
182979119Sbrian      break;
183037210Sbrian    } else
183178410Sbrian      *change = long_val;
183278410Sbrian    if (l->lcp.cfg.mru > *change)
183378410Sbrian      l->lcp.cfg.mru = *change;
183428679Sbrian    break;
183537210Sbrian
183636285Sbrian  case VAR_MTU:
183779163Sbrian    long_val = 0;	/* silence gcc */
183879163Sbrian    change = NULL;	/* silence gcc */
183978410Sbrian    switch(arg->argc - arg->argn) {
184078410Sbrian    case 1:
184179119Sbrian      if (argp[strspn(argp, "0123456789")] != '\0') {
184279119Sbrian        res = -1;
184379119Sbrian        break;
184479119Sbrian      }
184579119Sbrian      /*FALLTHRU*/
184678410Sbrian    case 0:
184778410Sbrian      long_val = atol(argp);
184878410Sbrian      change = &l->lcp.cfg.mtu;
184978410Sbrian      if (long_val > l->lcp.cfg.max_mtu) {
185078410Sbrian        log_Printf(LogWARN, "MTU %ld: too large - max set to %d\n", long_val,
185178410Sbrian                   l->lcp.cfg.max_mtu);
185279119Sbrian        res = 1;
185379119Sbrian        break;
185478410Sbrian      }
185578410Sbrian      break;
185678410Sbrian    case 2:
185779119Sbrian      if (strcasecmp(argp, "max") && strcasecmp(argp, "maximum")) {
185879119Sbrian        res = -1;
185979119Sbrian        break;
186079119Sbrian      }
186178410Sbrian      long_val = atol(arg->argv[arg->argn + 1]);
186278410Sbrian      change = &l->lcp.cfg.max_mtu;
186378410Sbrian      if (long_val > MAX_MTU) {
186478410Sbrian        log_Printf(LogWARN, "MTU %ld: too large - maximum is %d\n", long_val,
186578410Sbrian                   MAX_MTU);
186679119Sbrian        res = 1;
186779119Sbrian        break;
186878410Sbrian      }
186978410Sbrian      break;
187078410Sbrian    default:
187179119Sbrian      res = -1;
187279119Sbrian      break;
187378410Sbrian    }
187478410Sbrian
187579119Sbrian    if (res != 0)
187679119Sbrian      break;
187779119Sbrian
187837210Sbrian    if (long_val && long_val < MIN_MTU) {
187937210Sbrian      log_Printf(LogWARN, "MTU %ld: too small - min %d\n", long_val, MIN_MTU);
188079119Sbrian      res = 1;
188179119Sbrian      break;
188237210Sbrian    } else if (long_val > MAX_MTU) {
188337210Sbrian      log_Printf(LogWARN, "MTU %ld: too big - max %d\n", long_val, MAX_MTU);
188479119Sbrian      res = 1;
188579119Sbrian      break;
188637210Sbrian    } else
188778410Sbrian      *change = long_val;
188878410Sbrian    if (l->lcp.cfg.mtu > *change)
188978410Sbrian      l->lcp.cfg.mtu = *change;
189036285Sbrian    break;
189137210Sbrian
189236285Sbrian  case VAR_OPENMODE:
189336285Sbrian    if (strcasecmp(argp, "active") == 0)
189436285Sbrian      cx->physical->link.lcp.cfg.openmode = arg->argc > arg->argn+1 ?
189536285Sbrian        atoi(arg->argv[arg->argn+1]) : 1;
189636285Sbrian    else if (strcasecmp(argp, "passive") == 0)
189736285Sbrian      cx->physical->link.lcp.cfg.openmode = OPEN_PASSIVE;
189836285Sbrian    else {
189979119Sbrian      log_Printf(LogWARN, "%s: Invalid openmode\n", argp);
190079119Sbrian      res = 1;
190136285Sbrian    }
190236285Sbrian    break;
190337210Sbrian
190428679Sbrian  case VAR_PHONE:
190536285Sbrian    strncpy(cx->cfg.phone.list, argp, sizeof cx->cfg.phone.list - 1);
190636285Sbrian    cx->cfg.phone.list[sizeof cx->cfg.phone.list - 1] = '\0';
190738174Sbrian    cx->phone.alt = cx->phone.next = NULL;
190828679Sbrian    break;
190937210Sbrian
191028679Sbrian  case VAR_HANGUP:
191136285Sbrian    strncpy(cx->cfg.script.hangup, argp, sizeof cx->cfg.script.hangup - 1);
191236285Sbrian    cx->cfg.script.hangup[sizeof cx->cfg.script.hangup - 1] = '\0';
191328679Sbrian    break;
191437210Sbrian
191561534Sbrian  case VAR_IFQUEUE:
191661534Sbrian    long_val = atol(argp);
191761534Sbrian    arg->bundle->cfg.ifqueue = long_val < 0 ? 0 : long_val;
191861534Sbrian    break;
191961534Sbrian
192052488Sbrian  case VAR_LOGOUT:
192152488Sbrian    strncpy(cx->cfg.script.logout, argp, sizeof cx->cfg.script.logout - 1);
192252488Sbrian    cx->cfg.script.logout[sizeof cx->cfg.script.logout - 1] = '\0';
192352488Sbrian    break;
192452488Sbrian
192536285Sbrian  case VAR_IDLETIMEOUT:
192679119Sbrian    if (arg->argc > arg->argn+2) {
192779119Sbrian      log_Printf(LogWARN, "Too many idle timeout values\n");
192879119Sbrian      res = 1;
192979119Sbrian    } else if (arg->argc == arg->argn) {
193079119Sbrian      log_Printf(LogWARN, "Too few idle timeout values\n");
193179119Sbrian      res = 1;
193279119Sbrian    } else {
193349978Sbrian      int timeout, min;
193449978Sbrian
193549978Sbrian      timeout = atoi(argp);
193649978Sbrian      min = arg->argc == arg->argn + 2 ? atoi(arg->argv[arg->argn + 1]) : -1;
193749978Sbrian      bundle_SetIdleTimer(arg->bundle, timeout, min);
193849978Sbrian    }
193929549Sbrian    break;
194037210Sbrian
194136285Sbrian  case VAR_LQRPERIOD:
194237210Sbrian    long_val = atol(argp);
194337210Sbrian    if (long_val < MIN_LQRPERIOD) {
194437210Sbrian      log_Printf(LogWARN, "%ld: Invalid lqr period - min %d\n",
194537210Sbrian                 long_val, MIN_LQRPERIOD);
194679119Sbrian      res = 1;
194736285Sbrian    } else
194837210Sbrian      l->lcp.cfg.lqrperiod = long_val;
194936285Sbrian    break;
195037210Sbrian
195136285Sbrian  case VAR_LCPRETRY:
195279119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
195379119Sbrian                   &cx->physical->link.lcp.cfg.fsm.timeout,
195479119Sbrian                   &cx->physical->link.lcp.cfg.fsm.maxreq,
195579119Sbrian                   &cx->physical->link.lcp.cfg.fsm.maxtrm, DEF_FSMTRIES);
195636285Sbrian    break;
195737210Sbrian
195836285Sbrian  case VAR_CHAPRETRY:
195979119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
196079119Sbrian                   &cx->chap.auth.cfg.fsm.timeout,
196179119Sbrian                   &cx->chap.auth.cfg.fsm.maxreq, NULL, DEF_FSMAUTHTRIES);
196236285Sbrian    break;
196337210Sbrian
196436285Sbrian  case VAR_PAPRETRY:
196579119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
196679119Sbrian                   &cx->pap.cfg.fsm.timeout, &cx->pap.cfg.fsm.maxreq,
196779119Sbrian                   NULL, DEF_FSMAUTHTRIES);
196836285Sbrian    break;
196937210Sbrian
197036285Sbrian  case VAR_CCPRETRY:
197179119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
197279119Sbrian                   &l->ccp.cfg.fsm.timeout, &l->ccp.cfg.fsm.maxreq,
197379119Sbrian                   &l->ccp.cfg.fsm.maxtrm, DEF_FSMTRIES);
197436285Sbrian    break;
197537210Sbrian
197636285Sbrian  case VAR_IPCPRETRY:
197779119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
197879119Sbrian                   &arg->bundle->ncp.ipcp.cfg.fsm.timeout,
197979119Sbrian                   &arg->bundle->ncp.ipcp.cfg.fsm.maxreq,
198079119Sbrian                   &arg->bundle->ncp.ipcp.cfg.fsm.maxtrm, DEF_FSMTRIES);
198136285Sbrian    break;
198237210Sbrian
198336285Sbrian  case VAR_NBNS:
198436285Sbrian  case VAR_DNS:
198558044Sbrian    if (param == VAR_DNS) {
198681634Sbrian      ipaddr = arg->bundle->ncp.ipcp.cfg.ns.dns;
198781634Sbrian      ipaddr[0].s_addr = ipaddr[1].s_addr = INADDR_NONE;
198858044Sbrian    } else {
198981634Sbrian      ipaddr = arg->bundle->ncp.ipcp.cfg.ns.nbns;
199081634Sbrian      ipaddr[0].s_addr = ipaddr[1].s_addr = INADDR_ANY;
199158044Sbrian    }
199236285Sbrian
199336285Sbrian    if (arg->argc > arg->argn) {
199481634Sbrian      ncpaddr_aton(ncpaddr, &arg->bundle->ncp, arg->argv[arg->argn]);
199581634Sbrian      if (!ncpaddr_getip4(ncpaddr, ipaddr))
199681634Sbrian        return -1;
199781634Sbrian      if (arg->argc > arg->argn+1) {
199881634Sbrian        ncpaddr_aton(ncpaddr + 1, &arg->bundle->ncp, arg->argv[arg->argn + 1]);
199981634Sbrian        if (!ncpaddr_getip4(ncpaddr + 1, ipaddr + 1))
200081634Sbrian          return -1;
200181634Sbrian      }
200236285Sbrian
200381634Sbrian      if (ipaddr[0].s_addr == INADDR_ANY) {
200481634Sbrian        ipaddr[0] = ipaddr[1];
200581634Sbrian        ipaddr[1].s_addr = INADDR_ANY;
200658044Sbrian      }
200781634Sbrian      if (ipaddr[0].s_addr == INADDR_NONE) {
200881634Sbrian        ipaddr[0] = ipaddr[1];
200981634Sbrian        ipaddr[1].s_addr = INADDR_NONE;
201058044Sbrian      }
201136285Sbrian    }
201236285Sbrian    break;
201338174Sbrian
201438174Sbrian  case VAR_CALLBACK:
201538174Sbrian    cx->cfg.callback.opmask = 0;
201638174Sbrian    for (dummyint = arg->argn; dummyint < arg->argc; dummyint++) {
201738174Sbrian      if (!strcasecmp(arg->argv[dummyint], "auth"))
201838174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_AUTH);
201938174Sbrian      else if (!strcasecmp(arg->argv[dummyint], "cbcp"))
202038174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_CBCP);
202138174Sbrian      else if (!strcasecmp(arg->argv[dummyint], "e.164")) {
202238174Sbrian        if (dummyint == arg->argc - 1)
202338174Sbrian          log_Printf(LogWARN, "No E.164 arg (E.164 ignored) !\n");
202438174Sbrian        else {
202538174Sbrian          cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_E164);
202638174Sbrian          strncpy(cx->cfg.callback.msg, arg->argv[++dummyint],
202738174Sbrian                  sizeof cx->cfg.callback.msg - 1);
202838174Sbrian          cx->cfg.callback.msg[sizeof cx->cfg.callback.msg - 1] = '\0';
202938174Sbrian        }
203038174Sbrian      } else if (!strcasecmp(arg->argv[dummyint], "none"))
203138174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_NONE);
203279119Sbrian      else {
203379119Sbrian        res = -1;
203479119Sbrian        break;
203579119Sbrian      }
203638174Sbrian    }
203738174Sbrian    if (cx->cfg.callback.opmask == CALLBACK_BIT(CALLBACK_NONE))
203838174Sbrian      cx->cfg.callback.opmask = 0;
203938174Sbrian    break;
204038174Sbrian
204138174Sbrian  case VAR_CBCP:
204238174Sbrian    cx->cfg.cbcp.delay = 0;
204338174Sbrian    *cx->cfg.cbcp.phone = '\0';
204438174Sbrian    cx->cfg.cbcp.fsmretry = DEF_FSMRETRY;
204538174Sbrian    if (arg->argc > arg->argn) {
204638174Sbrian      strncpy(cx->cfg.cbcp.phone, arg->argv[arg->argn],
204738174Sbrian              sizeof cx->cfg.cbcp.phone - 1);
204838174Sbrian      cx->cfg.cbcp.phone[sizeof cx->cfg.cbcp.phone - 1] = '\0';
204938174Sbrian      if (arg->argc > arg->argn + 1) {
205038174Sbrian        cx->cfg.cbcp.delay = atoi(arg->argv[arg->argn + 1]);
205138174Sbrian        if (arg->argc > arg->argn + 2) {
205238174Sbrian          long_val = atol(arg->argv[arg->argn + 2]);
205338174Sbrian          if (long_val < MIN_FSMRETRY)
205438174Sbrian            log_Printf(LogWARN, "%ld: Invalid CBCP FSM retry period - min %d\n",
205538174Sbrian                       long_val, MIN_FSMRETRY);
205638174Sbrian          else
205738174Sbrian            cx->cfg.cbcp.fsmretry = long_val;
205838174Sbrian        }
205938174Sbrian      }
206038174Sbrian    }
206138174Sbrian    break;
206238544Sbrian
206338544Sbrian  case VAR_CHOKED:
206438544Sbrian    arg->bundle->cfg.choked.timeout = atoi(argp);
206538544Sbrian    if (arg->bundle->cfg.choked.timeout <= 0)
206638544Sbrian      arg->bundle->cfg.choked.timeout = CHOKED_TIMEOUT;
206738544Sbrian    break;
206840665Sbrian
206940665Sbrian  case VAR_SENDPIPE:
207040665Sbrian    long_val = atol(argp);
207181634Sbrian    arg->bundle->ncp.cfg.sendpipe = long_val;
207240665Sbrian    break;
207340665Sbrian
207440665Sbrian  case VAR_RECVPIPE:
207540665Sbrian    long_val = atol(argp);
207681634Sbrian    arg->bundle->ncp.cfg.recvpipe = long_val;
207740665Sbrian    break;
207843313Sbrian
207943313Sbrian#ifndef NORADIUS
208043313Sbrian  case VAR_RADIUS:
208143313Sbrian    if (!*argp)
208243313Sbrian      *arg->bundle->radius.cfg.file = '\0';
208343313Sbrian    else if (access(argp, R_OK)) {
208443313Sbrian      log_Printf(LogWARN, "%s: %s\n", argp, strerror(errno));
208579119Sbrian      res = 1;
208679119Sbrian      break;
208743313Sbrian    } else {
208843313Sbrian      strncpy(arg->bundle->radius.cfg.file, argp,
208943313Sbrian              sizeof arg->bundle->radius.cfg.file - 1);
209043313Sbrian      arg->bundle->radius.cfg.file
209143313Sbrian        [sizeof arg->bundle->radius.cfg.file - 1] = '\0';
209243313Sbrian    }
209343313Sbrian    break;
209443313Sbrian#endif
209544073Sbrian
209644073Sbrian  case VAR_CD:
209744073Sbrian    if (*argp) {
209851699Sbrian      if (strcasecmp(argp, "off")) {
209951699Sbrian        long_val = atol(argp);
210051699Sbrian        if (long_val < 0)
210151699Sbrian          long_val = 0;
210251699Sbrian        cx->physical->cfg.cd.delay = long_val;
210351699Sbrian        cx->physical->cfg.cd.necessity = argp[strlen(argp)-1] == '!' ?
210451699Sbrian          CD_REQUIRED : CD_VARIABLE;
210551699Sbrian      } else
210651699Sbrian        cx->physical->cfg.cd.necessity = CD_NOTREQUIRED;
210744073Sbrian    } else {
210853733Sbrian      cx->physical->cfg.cd.delay = 0;
210953733Sbrian      cx->physical->cfg.cd.necessity = CD_DEFAULT;
211044073Sbrian    }
211144073Sbrian    break;
211236285Sbrian
211346686Sbrian  case VAR_PARITY:
211446686Sbrian    if (arg->argc == arg->argn + 1)
211579119Sbrian      res = physical_SetParity(arg->cx->physical, argp);
211646686Sbrian    else {
211779119Sbrian      log_Printf(LogWARN, "Parity value must be odd, even or none\n");
211879119Sbrian      res = 1;
211946686Sbrian    }
212046686Sbrian    break;
21216059Samurai
212246686Sbrian  case VAR_CRTSCTS:
212346686Sbrian    if (strcasecmp(argp, "on") == 0)
212436285Sbrian      physical_SetRtsCts(arg->cx->physical, 1);
212546686Sbrian    else if (strcasecmp(argp, "off") == 0)
212636285Sbrian      physical_SetRtsCts(arg->cx->physical, 0);
212746686Sbrian    else {
212879119Sbrian      log_Printf(LogWARN, "RTS/CTS value must be on or off\n");
212979119Sbrian      res = 1;
213046686Sbrian    }
213146686Sbrian    break;
213250867Sbrian
213350867Sbrian  case VAR_URGENTPORTS:
213451048Sbrian    if (arg->argn == arg->argc) {
213581634Sbrian      ncp_SetUrgentTOS(&arg->bundle->ncp);
213681634Sbrian      ncp_ClearUrgentTcpPorts(&arg->bundle->ncp);
213781634Sbrian      ncp_ClearUrgentUdpPorts(&arg->bundle->ncp);
213851048Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "udp")) {
213981634Sbrian      ncp_SetUrgentTOS(&arg->bundle->ncp);
214051048Sbrian      if (arg->argn == arg->argc - 1)
214181634Sbrian        ncp_ClearUrgentUdpPorts(&arg->bundle->ncp);
214251048Sbrian      else for (f = arg->argn + 1; f < arg->argc; f++)
214351048Sbrian        if (*arg->argv[f] == '+')
214481634Sbrian          ncp_AddUrgentUdpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1));
214551048Sbrian        else if (*arg->argv[f] == '-')
214681634Sbrian          ncp_RemoveUrgentUdpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1));
214751048Sbrian        else {
214851048Sbrian          if (f == arg->argn)
214981634Sbrian            ncp_ClearUrgentUdpPorts(&arg->bundle->ncp);
215081634Sbrian          ncp_AddUrgentUdpPort(&arg->bundle->ncp, atoi(arg->argv[f]));
215151048Sbrian        }
215261430Sbrian    } else if (arg->argn == arg->argc - 1 &&
215361430Sbrian               !strcasecmp(arg->argv[arg->argn], "none")) {
215481634Sbrian      ncp_ClearUrgentTcpPorts(&arg->bundle->ncp);
215581634Sbrian      ncp_ClearUrgentUdpPorts(&arg->bundle->ncp);
215681634Sbrian      ncp_ClearUrgentTOS(&arg->bundle->ncp);
215751048Sbrian    } else {
215881634Sbrian      ncp_SetUrgentTOS(&arg->bundle->ncp);
215951048Sbrian      first = arg->argn;
216051048Sbrian      if (!strcasecmp(arg->argv[first], "tcp") && ++first == arg->argc)
216181634Sbrian        ncp_ClearUrgentTcpPorts(&arg->bundle->ncp);
216251048Sbrian
216351048Sbrian      for (f = first; f < arg->argc; f++)
216451048Sbrian        if (*arg->argv[f] == '+')
216581634Sbrian          ncp_AddUrgentTcpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1));
216651048Sbrian        else if (*arg->argv[f] == '-')
216781634Sbrian          ncp_RemoveUrgentTcpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1));
216851048Sbrian        else {
216951048Sbrian          if (f == first)
217081634Sbrian            ncp_ClearUrgentTcpPorts(&arg->bundle->ncp);
217181634Sbrian          ncp_AddUrgentTcpPort(&arg->bundle->ncp, atoi(arg->argv[f]));
217251048Sbrian        }
217351048Sbrian    }
217450867Sbrian    break;
217520812Sjkh  }
217646686Sbrian
217779119Sbrian  return res;
217820812Sjkh}
217920812Sjkh
218030715Sbrianstatic struct cmdtab const SetCommands[] = {
218136285Sbrian  {"accmap", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
218236285Sbrian  "accmap value", "set accmap hex-value", (const void *)VAR_ACCMAP},
218328679Sbrian  {"authkey", "key", SetVariable, LOCAL_AUTH,
218436285Sbrian  "authentication key", "set authkey|key key", (const void *)VAR_AUTHKEY},
218528679Sbrian  {"authname", NULL, SetVariable, LOCAL_AUTH,
218636285Sbrian  "authentication name", "set authname name", (const void *)VAR_AUTHNAME},
218736285Sbrian  {"autoload", NULL, SetVariable, LOCAL_AUTH,
218836285Sbrian  "auto link [de]activation", "set autoload maxtime maxload mintime minload",
218936285Sbrian  (const void *)VAR_AUTOLOAD},
219050867Sbrian  {"bandwidth", NULL, mp_SetDatalinkBandwidth, LOCAL_AUTH | LOCAL_CX,
219150867Sbrian  "datalink bandwidth", "set bandwidth value"},
219238174Sbrian  {"callback", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
219338174Sbrian  "callback control", "set callback [none|auth|cbcp|"
219438174Sbrian  "E.164 *|number[,number]...]...", (const void *)VAR_CALLBACK},
219538174Sbrian  {"cbcp", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
219638174Sbrian  "CBCP control", "set cbcp [*|phone[,phone...] [delay [timeout]]]",
219738174Sbrian  (const void *)VAR_CBCP},
219844305Sbrian  {"ccpretry", "ccpretries", SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
219944305Sbrian   "CCP retries", "set ccpretry value [attempts]", (const void *)VAR_CCPRETRY},
220044073Sbrian  {"cd", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "Carrier delay requirement",
220144073Sbrian   "set cd value[!]", (const void *)VAR_CD},
220244305Sbrian  {"chapretry", "chapretries", SetVariable, LOCAL_AUTH | LOCAL_CX,
220344305Sbrian   "CHAP retries", "set chapretry value [attempts]",
220444305Sbrian   (const void *)VAR_CHAPRETRY},
220538544Sbrian  {"choked", NULL, SetVariable, LOCAL_AUTH,
220638544Sbrian  "choked timeout", "set choked [secs]", (const void *)VAR_CHOKED},
220746686Sbrian  {"ctsrts", "crtscts", SetVariable, LOCAL_AUTH | LOCAL_CX,
220846686Sbrian   "Use hardware flow control", "set ctsrts [on|off]",
220946686Sbrian   (const char *)VAR_CRTSCTS},
221036285Sbrian  {"deflate", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
221136285Sbrian  "deflate window sizes", "set deflate out-winsize in-winsize",
221236285Sbrian  (const void *) VAR_WINSIZE},
221367910Sbrian#ifdef HAVE_DES
221467910Sbrian  {"mppe", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
221579370Sbrian  "MPPE key size and state", "set mppe [40|56|128|* [stateful|stateless|*]]",
221678411Sbrian  (const void *) VAR_MPPE},
221767910Sbrian#endif
221836285Sbrian  {"device", "line", SetVariable, LOCAL_AUTH | LOCAL_CX,
221946686Sbrian  "physical device name", "set device|line device-name[,device-name]",
222036285Sbrian  (const void *) VAR_DEVICE},
222136285Sbrian  {"dial", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
222236285Sbrian  "dialing script", "set dial chat-script", (const void *) VAR_DIAL},
222336285Sbrian  {"dns", NULL, SetVariable, LOCAL_AUTH, "Domain Name Server",
222436285Sbrian  "set dns pri-addr [sec-addr]", (const void *)VAR_DNS},
222536285Sbrian  {"enddisc", NULL, mp_SetEnddisc, LOCAL_AUTH,
222636285Sbrian  "Endpoint Discriminator", "set enddisc [IP|magic|label|psn value]"},
222736285Sbrian  {"escape", NULL, SetEscape, LOCAL_AUTH | LOCAL_CX,
222836285Sbrian  "escape characters", "set escape hex-digit ..."},
222936285Sbrian  {"filter", NULL, filter_Set, LOCAL_AUTH,
223036285Sbrian  "packet filters", "set filter alive|dial|in|out rule-no permit|deny "
223181634Sbrian  "[src_addr[/width]] [dst_addr[/width]] [proto "
223248142Sbrian  "[src [lt|eq|gt port]] [dst [lt|eq|gt port]] [estab] [syn] [finrst]]"},
223336285Sbrian  {"hangup", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
223436285Sbrian  "hangup script", "set hangup chat-script", (const void *) VAR_HANGUP},
223536285Sbrian  {"ifaddr", NULL, SetInterfaceAddr, LOCAL_AUTH, "destination address",
223631343Sbrian  "set ifaddr [src-addr [dst-addr [netmask [trg-addr]]]]"},
223761534Sbrian  {"ifqueue", NULL, SetVariable, LOCAL_AUTH, "interface queue",
223861534Sbrian  "set ifqueue packets", (const void *)VAR_IFQUEUE},
223944305Sbrian  {"ipcpretry", "ipcpretries", SetVariable, LOCAL_AUTH, "IPCP retries",
224044305Sbrian   "set ipcpretry value [attempts]", (const void *)VAR_IPCPRETRY},
224144305Sbrian  {"lcpretry", "lcpretries", SetVariable, LOCAL_AUTH | LOCAL_CX, "LCP retries",
224244305Sbrian   "set lcpretry value [attempts]", (const void *)VAR_LCPRETRY},
224336712Sbrian  {"log", NULL, log_SetLevel, LOCAL_AUTH, "log level",
224467916Sbrian  "set log [local] [+|-]all|async|cbcp|ccp|chat|command|connect|debug|dns|hdlc|"
224558033Sbrian  "id0|ipcp|lcp|lqm|phase|physical|sync|tcp/ip|timer|tun..."},
224636285Sbrian  {"login", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
224736285Sbrian  "login script", "set login chat-script", (const void *) VAR_LOGIN},
224852488Sbrian  {"logout", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
224952488Sbrian  "logout script", "set logout chat-script", (const void *) VAR_LOGOUT},
225036285Sbrian  {"lqrperiod", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
225136285Sbrian  "LQR period", "set lqrperiod value", (const void *)VAR_LQRPERIOD},
225236285Sbrian  {"mode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "mode value",
225336285Sbrian  "set mode interactive|auto|ddial|background", (const void *)VAR_MODE},
225436285Sbrian  {"mrru", NULL, SetVariable, LOCAL_AUTH, "MRRU value",
225536285Sbrian  "set mrru value", (const void *)VAR_MRRU},
225636285Sbrian  {"mru", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
225778410Sbrian  "MRU value", "set mru [max[imum]] [value]", (const void *)VAR_MRU},
225878410Sbrian  {"mtu", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
225978410Sbrian  "interface MTU value", "set mtu [max[imum]] [value]", (const void *)VAR_MTU},
226036285Sbrian  {"nbns", NULL, SetVariable, LOCAL_AUTH, "NetBIOS Name Server",
226136285Sbrian  "set nbns pri-addr [sec-addr]", (const void *)VAR_NBNS},
226236285Sbrian  {"openmode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "open mode",
226336285Sbrian  "set openmode active|passive [secs]", (const void *)VAR_OPENMODE},
226444305Sbrian  {"papretry", "papretries", SetVariable, LOCAL_AUTH | LOCAL_CX, "PAP retries",
226544305Sbrian   "set papretry value [attempts]", (const void *)VAR_PAPRETRY},
226646686Sbrian  {"parity", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "serial parity",
226746686Sbrian   "set parity [odd|even|none]", (const void *)VAR_PARITY},
226836285Sbrian  {"phone", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "telephone number(s)",
226936285Sbrian  "set phone phone1[:phone2[...]]", (const void *)VAR_PHONE},
227040679Sbrian  {"proctitle", "title", SetProcTitle, LOCAL_AUTH,
227140679Sbrian  "Process title", "set proctitle [value]"},
227243313Sbrian#ifndef NORADIUS
227343313Sbrian  {"radius", NULL, SetVariable, LOCAL_AUTH,
227443313Sbrian  "RADIUS Config", "set radius cfgfile", (const void *)VAR_RADIUS},
227543313Sbrian#endif
227636285Sbrian  {"reconnect", NULL, datalink_SetReconnect, LOCAL_AUTH | LOCAL_CX,
227736285Sbrian  "Reconnect timeout", "set reconnect value ntries"},
227840665Sbrian  {"recvpipe", NULL, SetVariable, LOCAL_AUTH,
227940665Sbrian  "RECVPIPE value", "set recvpipe value", (const void *)VAR_RECVPIPE},
228036285Sbrian  {"redial", NULL, datalink_SetRedial, LOCAL_AUTH | LOCAL_CX,
228144468Sbrian  "Redial timeout", "set redial secs[+inc[-incmax]][.next] [attempts]"},
228240665Sbrian  {"sendpipe", NULL, SetVariable, LOCAL_AUTH,
228340665Sbrian  "SENDPIPE value", "set sendpipe value", (const void *)VAR_SENDPIPE},
228471657Sbrian  {"server", "socket", SetServer, LOCAL_AUTH, "diagnostic port",
228571657Sbrian  "set server|socket TcpPort|LocalName|none|open|closed [password [mask]]"},
228636285Sbrian  {"speed", NULL, SetModemSpeed, LOCAL_AUTH | LOCAL_CX,
228746686Sbrian  "physical speed", "set speed value|sync"},
228836285Sbrian  {"stopped", NULL, SetStoppedTimeout, LOCAL_AUTH | LOCAL_CX,
228936285Sbrian  "STOPPED timeouts", "set stopped [LCPseconds [CCPseconds]]"},
229036285Sbrian  {"timeout", NULL, SetVariable, LOCAL_AUTH, "Idle timeout",
229136285Sbrian  "set timeout idletime", (const void *)VAR_IDLETIMEOUT},
229251048Sbrian  {"urgent", NULL, SetVariable, LOCAL_AUTH, "urgent ports",
229351048Sbrian  "set urgent [tcp|udp] [+|-]port...", (const void *)VAR_URGENTPORTS},
229436285Sbrian  {"vj", NULL, ipcp_vjset, LOCAL_AUTH,
229536285Sbrian  "vj values", "set vj slots|slotcomp [value]"},
229628679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
229731343Sbrian  "Display this message", "set help|? [command]", SetCommands},
229828679Sbrian  {NULL, NULL, NULL},
22996059Samurai};
23006059Samurai
23016059Samuraistatic int
230231343SbrianSetCommand(struct cmdargs const *arg)
23036059Samurai{
230436285Sbrian  if (arg->argc > arg->argn)
230536285Sbrian    FindExec(arg->bundle, SetCommands, arg->argc, arg->argn, arg->argv,
230636285Sbrian             arg->prompt, arg->cx);
230736285Sbrian  else if (arg->prompt)
230836285Sbrian    prompt_Printf(arg->prompt, "Use `set ?' to get a list or `set ? <var>' for"
230958044Sbrian	          " syntax help.\n");
23106059Samurai  else
231136285Sbrian    log_Printf(LogWARN, "set command must have arguments\n");
231226516Sbrian
231326516Sbrian  return 0;
23146059Samurai}
23156059Samurai
23166059Samuraistatic int
231731343SbrianAddCommand(struct cmdargs const *arg)
23186059Samurai{
231981634Sbrian  struct ncpaddr gw;
232081634Sbrian  struct ncprange dest;
232181634Sbrian  struct in_addr host;
232281634Sbrian  int dest_default, gw_arg, addrs;
23236059Samurai
232436285Sbrian  if (arg->argc != arg->argn+3 && arg->argc != arg->argn+2)
232531598Sbrian    return -1;
232631598Sbrian
232736285Sbrian  addrs = 0;
232881634Sbrian  dest_default = 0;
232981634Sbrian  if (arg->argc == arg->argn + 2) {
233036285Sbrian    if (!strcasecmp(arg->argv[arg->argn], "default"))
233181634Sbrian      dest_default = 1;
233231598Sbrian    else {
233381634Sbrian      if (!ncprange_aton(&dest, &arg->bundle->ncp, arg->argv[arg->argn]))
233436285Sbrian        return -1;
233536285Sbrian      if (!strncasecmp(arg->argv[arg->argn], "MYADDR", 6))
233636285Sbrian        addrs = ROUTE_DSTMYADDR;
233781634Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "MYADDR6", 7))
233881634Sbrian        addrs = ROUTE_DSTMYADDR6;
233936285Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "HISADDR", 7))
234036285Sbrian        addrs = ROUTE_DSTHISADDR;
234181634Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "HISADDR6", 8))
234281634Sbrian        addrs = ROUTE_DSTHISADDR6;
234358044Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "DNS0", 4))
234458044Sbrian        addrs = ROUTE_DSTDNS0;
234558044Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "DNS1", 4))
234658044Sbrian        addrs = ROUTE_DSTDNS1;
234731598Sbrian    }
234881634Sbrian    gw_arg = 1;
234934536Sbrian  } else {
235036285Sbrian    if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
235136285Sbrian      addrs = ROUTE_DSTMYADDR;
235281634Sbrian      host = arg->bundle->ncp.ipcp.my_ip;
235336285Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
235436285Sbrian      addrs = ROUTE_DSTHISADDR;
235581634Sbrian      host = arg->bundle->ncp.ipcp.peer_ip;
235658044Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "DNS0") == 0) {
235758044Sbrian      addrs = ROUTE_DSTDNS0;
235881634Sbrian      host = arg->bundle->ncp.ipcp.ns.dns[0];
235958044Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "DNS1") == 0) {
236058044Sbrian      addrs = ROUTE_DSTDNS1;
236181634Sbrian      host = arg->bundle->ncp.ipcp.ns.dns[1];
236265263Sbrian    } else {
236381634Sbrian      host = GetIpAddr(arg->argv[arg->argn]);
236481634Sbrian      if (host.s_addr == INADDR_NONE) {
236565263Sbrian        log_Printf(LogWARN, "%s: Invalid destination address\n",
236665263Sbrian                   arg->argv[arg->argn]);
236765263Sbrian        return -1;
236865263Sbrian      }
236965263Sbrian    }
237081634Sbrian    ncprange_setip4(&dest, host, GetIpAddr(arg->argv[arg->argn + 1]));
237181634Sbrian    gw_arg = 2;
23726059Samurai  }
237336285Sbrian
237481634Sbrian  if (strcasecmp(arg->argv[arg->argn + gw_arg], "HISADDR") == 0) {
237581634Sbrian    ncpaddr_setip4(&gw, arg->bundle->ncp.ipcp.peer_ip);
237636285Sbrian    addrs |= ROUTE_GWHISADDR;
237781634Sbrian#ifndef NOINET6
237881897Sbrian  } else if (strcasecmp(arg->argv[arg->argn + gw_arg], "HISADDR6") == 0) {
237981634Sbrian    ncpaddr_copy(&gw, &arg->bundle->ncp.ipv6cp.hisaddr);
238081634Sbrian    addrs |= ROUTE_GWHISADDR6;
238181634Sbrian#endif
238265263Sbrian  } else {
238381634Sbrian    if (!ncpaddr_aton(&gw, &arg->bundle->ncp, arg->argv[arg->argn + gw_arg])) {
238465263Sbrian      log_Printf(LogWARN, "%s: Invalid gateway address\n",
238581634Sbrian                 arg->argv[arg->argn + gw_arg]);
238665263Sbrian      return -1;
238765263Sbrian    }
238865263Sbrian  }
238936285Sbrian
239081634Sbrian  if (dest_default)
239181634Sbrian    ncprange_setdefault(&dest, ncpaddr_family(&gw));
239281634Sbrian
239381634Sbrian  if (rt_Set(arg->bundle, RTM_ADD, &dest, &gw, arg->cmd->args ? 1 : 0,
239481634Sbrian             ((addrs & ROUTE_GWHISADDR) || (addrs & ROUTE_GWHISADDR6)) ? 1 : 0)
239543313Sbrian      && addrs != ROUTE_STATIC)
239681634Sbrian    route_Add(&arg->bundle->ncp.route, addrs, &dest, &gw);
239736285Sbrian
239831598Sbrian  return 0;
23996059Samurai}
24006059Samurai
24016059Samuraistatic int
240231343SbrianDeleteCommand(struct cmdargs const *arg)
24036059Samurai{
240481634Sbrian  struct ncprange dest;
240536285Sbrian  int addrs;
24066059Samurai
240736285Sbrian  if (arg->argc == arg->argn+1) {
240836285Sbrian    if(strcasecmp(arg->argv[arg->argn], "all") == 0) {
240936285Sbrian      route_IfDelete(arg->bundle, 0);
241081634Sbrian      route_DeleteAll(&arg->bundle->ncp.route);
241136285Sbrian    } else {
241236285Sbrian      addrs = 0;
241336285Sbrian      if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
241481634Sbrian        ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.my_ip);
241536285Sbrian        addrs = ROUTE_DSTMYADDR;
241681634Sbrian#ifndef NOINET6
241781897Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "MYADDR6") == 0) {
241881634Sbrian        ncprange_sethost(&dest, &arg->bundle->ncp.ipv6cp.myaddr);
241981634Sbrian        addrs = ROUTE_DSTMYADDR6;
242081634Sbrian#endif
242136285Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
242281634Sbrian        ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.peer_ip);
242336285Sbrian        addrs = ROUTE_DSTHISADDR;
242481634Sbrian#ifndef NOINET6
242581897Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "HISADDR6") == 0) {
242681634Sbrian        ncprange_sethost(&dest, &arg->bundle->ncp.ipv6cp.hisaddr);
242781634Sbrian        addrs = ROUTE_DSTHISADDR6;
242881634Sbrian#endif
242958044Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "DNS0") == 0) {
243081634Sbrian        ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.ns.dns[0]);
243158044Sbrian        addrs = ROUTE_DSTDNS0;
243258044Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "DNS1") == 0) {
243381634Sbrian        ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.ns.dns[1]);
243458044Sbrian        addrs = ROUTE_DSTDNS1;
243536285Sbrian      } else {
243681634Sbrian        ncprange_aton(&dest, &arg->bundle->ncp, arg->argv[arg->argn]);
243736285Sbrian        addrs = ROUTE_STATIC;
243836285Sbrian      }
243981634Sbrian      rt_Set(arg->bundle, RTM_DELETE, &dest, NULL, arg->cmd->args ? 1 : 0, 0);
244081634Sbrian      route_Delete(&arg->bundle->ncp.route, addrs, &dest);
244131598Sbrian    }
244234536Sbrian  } else
244326516Sbrian    return -1;
244426516Sbrian
244526516Sbrian  return 0;
24466059Samurai}
24476059Samurai
244850059Sbrian#ifndef NONAT
244926031Sbrianstatic int
245058867SbrianNatEnable(struct cmdargs const *arg)
245126031Sbrian{
245236285Sbrian  if (arg->argc == arg->argn+1) {
245336285Sbrian    if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
245450059Sbrian      if (!arg->bundle->NatEnabled) {
245546686Sbrian        if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED)
245646686Sbrian          PacketAliasSetAddress(arg->bundle->ncp.ipcp.my_ip);
245750059Sbrian        arg->bundle->NatEnabled = 1;
245846686Sbrian      }
245937191Sbrian      return 0;
246036285Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "no") == 0) {
246150059Sbrian      arg->bundle->NatEnabled = 0;
246240561Sbrian      arg->bundle->cfg.opt &= ~OPT_IFACEALIAS;
246340561Sbrian      /* Don't iface_Clear() - there may be manually configured addresses */
246426516Sbrian      return 0;
246526142Sbrian    }
246635449Sbrian  }
246736285Sbrian
246826516Sbrian  return -1;
246926031Sbrian}
247026031Sbrian
247126031Sbrian
247226031Sbrianstatic int
247358867SbrianNatOption(struct cmdargs const *arg)
247426031Sbrian{
247538559Sbrian  long param = (long)arg->cmd->args;
247638559Sbrian
247736285Sbrian  if (arg->argc == arg->argn+1) {
247836285Sbrian    if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
247950059Sbrian      if (arg->bundle->NatEnabled) {
248037191Sbrian	PacketAliasSetMode(param, param);
248128679Sbrian	return 0;
248228679Sbrian      }
248350059Sbrian      log_Printf(LogWARN, "nat not enabled\n");
248436285Sbrian    } else if (strcmp(arg->argv[arg->argn], "no") == 0) {
248550059Sbrian      if (arg->bundle->NatEnabled) {
248637191Sbrian	PacketAliasSetMode(0, param);
248728679Sbrian	return 0;
248828679Sbrian      }
248950059Sbrian      log_Printf(LogWARN, "nat not enabled\n");
249028679Sbrian    }
249135449Sbrian  }
249228679Sbrian  return -1;
249326031Sbrian}
249450059Sbrian#endif /* #ifndef NONAT */
249531121Sbrian
249631121Sbrianstatic int
249736285SbrianLinkCommand(struct cmdargs const *arg)
249836285Sbrian{
249936285Sbrian  if (arg->argc > arg->argn+1) {
250036285Sbrian    char namelist[LINE_LEN];
250136285Sbrian    struct datalink *cx;
250236285Sbrian    char *name;
250336285Sbrian    int result = 0;
250436285Sbrian
250536285Sbrian    if (!strcmp(arg->argv[arg->argn], "*")) {
250636285Sbrian      struct datalink *dl;
250736285Sbrian
250836285Sbrian      cx = arg->bundle->links;
250936285Sbrian      while (cx) {
251036285Sbrian        /* Watch it, the command could be a ``remove'' */
251136285Sbrian        dl = cx->next;
251236285Sbrian        FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
251336285Sbrian                 arg->prompt, cx);
251436285Sbrian        for (cx = arg->bundle->links; cx; cx = cx->next)
251536285Sbrian          if (cx == dl)
251636285Sbrian            break;		/* Pointer's still valid ! */
251736285Sbrian      }
251836285Sbrian    } else {
251936285Sbrian      strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
252036285Sbrian      namelist[sizeof namelist - 1] = '\0';
252136285Sbrian      for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
252236285Sbrian        if (!bundle2datalink(arg->bundle, name)) {
252336285Sbrian          log_Printf(LogWARN, "link: %s: Invalid link name\n", name);
252436285Sbrian          return 1;
252536285Sbrian        }
252636285Sbrian
252736285Sbrian      strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
252836285Sbrian      namelist[sizeof namelist - 1] = '\0';
252936285Sbrian      for(name = strtok(namelist, ", "); name; name = strtok(NULL,", ")) {
253036285Sbrian        cx = bundle2datalink(arg->bundle, name);
253136285Sbrian        if (cx)
253236285Sbrian          FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
253336285Sbrian                   arg->prompt, cx);
253436285Sbrian        else {
253536285Sbrian          log_Printf(LogWARN, "link: %s: Invalidated link name !\n", name);
253636285Sbrian          result++;
253736285Sbrian        }
253836285Sbrian      }
253936285Sbrian    }
254036285Sbrian    return result;
254136285Sbrian  }
254236285Sbrian
254336285Sbrian  log_Printf(LogWARN, "Usage: %s\n", arg->cmd->syntax);
254436285Sbrian  return 2;
254536285Sbrian}
254636285Sbrian
254736285Sbrianstruct link *
254836285Sbriancommand_ChooseLink(struct cmdargs const *arg)
254936285Sbrian{
255036285Sbrian  if (arg->cx)
255136285Sbrian    return &arg->cx->physical->link;
255237210Sbrian  else if (!arg->bundle->ncp.mp.cfg.mrru) {
255336285Sbrian    struct datalink *dl = bundle2datalink(arg->bundle, NULL);
255437210Sbrian    if (dl)
255537210Sbrian      return &dl->physical->link;
255636285Sbrian  }
255737210Sbrian  return &arg->bundle->ncp.mp.link;
255836285Sbrian}
255936285Sbrian
256036285Sbrianstatic const char *
256136285Sbrianident_cmd(const char *cmd, unsigned *keep, unsigned *add)
256236285Sbrian{
256336285Sbrian  const char *result;
256436285Sbrian
256536285Sbrian  switch (*cmd) {
256636285Sbrian    case 'A':
256736285Sbrian    case 'a':
256836285Sbrian      result = "accept";
256936285Sbrian      *keep = NEG_MYMASK;
257036285Sbrian      *add = NEG_ACCEPTED;
257136285Sbrian      break;
257236285Sbrian    case 'D':
257336285Sbrian    case 'd':
257436285Sbrian      switch (cmd[1]) {
257536285Sbrian        case 'E':
257636285Sbrian        case 'e':
257736285Sbrian          result = "deny";
257836285Sbrian          *keep = NEG_MYMASK;
257936285Sbrian          *add = 0;
258036285Sbrian          break;
258136285Sbrian        case 'I':
258236285Sbrian        case 'i':
258336285Sbrian          result = "disable";
258436285Sbrian          *keep = NEG_HISMASK;
258536285Sbrian          *add = 0;
258636285Sbrian          break;
258736285Sbrian        default:
258836285Sbrian          return NULL;
258936285Sbrian      }
259036285Sbrian      break;
259136285Sbrian    case 'E':
259236285Sbrian    case 'e':
259336285Sbrian      result = "enable";
259436285Sbrian      *keep = NEG_HISMASK;
259536285Sbrian      *add = NEG_ENABLED;
259636285Sbrian      break;
259736285Sbrian    default:
259836285Sbrian      return NULL;
259936285Sbrian  }
260036285Sbrian
260136285Sbrian  return result;
260236285Sbrian}
260336285Sbrian
260436285Sbrianstatic int
260536285SbrianOptSet(struct cmdargs const *arg)
260636285Sbrian{
260737574Sbrian  int bit = (int)(long)arg->cmd->args;
260836285Sbrian  unsigned keep;			/* Keep these bits */
260936285Sbrian  unsigned add;				/* Add these bits */
261036285Sbrian
261181697Sbrian  if (ident_cmd(arg->argv[arg->argn - 2], &keep, &add) == NULL)
261236285Sbrian    return 1;
261336285Sbrian
261481885Sbrian#ifndef NOINET6
261581697Sbrian  if (add == NEG_ENABLED && bit == OPT_IPV6CP && !probe.ipv6_available) {
261681697Sbrian    log_Printf(LogWARN, "IPv6 is not available on this machine\n");
261781697Sbrian    return 1;
261881697Sbrian  }
261981885Sbrian#endif
262081697Sbrian
262136285Sbrian  if (add)
262236285Sbrian    arg->bundle->cfg.opt |= bit;
262336285Sbrian  else
262436285Sbrian    arg->bundle->cfg.opt &= ~bit;
262581697Sbrian
262636285Sbrian  return 0;
262736285Sbrian}
262836285Sbrian
262936285Sbrianstatic int
263040561SbrianIfaceAliasOptSet(struct cmdargs const *arg)
263140561Sbrian{
263240561Sbrian  unsigned save = arg->bundle->cfg.opt;
263340561Sbrian  int result = OptSet(arg);
263440561Sbrian
263540561Sbrian  if (result == 0)
263650059Sbrian    if (Enabled(arg->bundle, OPT_IFACEALIAS) && !arg->bundle->NatEnabled) {
263740561Sbrian      arg->bundle->cfg.opt = save;
263850059Sbrian      log_Printf(LogWARN, "Cannot enable iface-alias without NAT\n");
263940561Sbrian      result = 2;
264040561Sbrian    }
264140561Sbrian
264240561Sbrian  return result;
264340561Sbrian}
264440561Sbrian
264540561Sbrianstatic int
264636285SbrianNegotiateSet(struct cmdargs const *arg)
264736285Sbrian{
264837210Sbrian  long param = (long)arg->cmd->args;
264936285Sbrian  struct link *l = command_ChooseLink(arg);	/* LOCAL_CX_OPT uses this */
265036285Sbrian  struct datalink *cx = arg->cx;	/* LOCAL_CX uses this */
265136285Sbrian  const char *cmd;
265236285Sbrian  unsigned keep;			/* Keep these bits */
265336285Sbrian  unsigned add;				/* Add these bits */
265436285Sbrian
265536285Sbrian  if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL)
265636285Sbrian    return 1;
265736285Sbrian
265836285Sbrian  if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
265936285Sbrian    log_Printf(LogWARN, "%s %s: No context (use the `link' command)\n",
266036285Sbrian              cmd, arg->cmd->name);
266136285Sbrian    return 2;
266236285Sbrian  } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
266336285Sbrian    log_Printf(LogWARN, "%s %s: Redundant context (%s) ignored\n",
266436285Sbrian              cmd, arg->cmd->name, cx->name);
266536285Sbrian    cx = NULL;
266636285Sbrian  }
266736285Sbrian
266836285Sbrian  switch (param) {
266936285Sbrian    case NEG_ACFCOMP:
267036285Sbrian      cx->physical->link.lcp.cfg.acfcomp &= keep;
267136285Sbrian      cx->physical->link.lcp.cfg.acfcomp |= add;
267236285Sbrian      break;
267344106Sbrian    case NEG_CHAP05:
267444106Sbrian      cx->physical->link.lcp.cfg.chap05 &= keep;
267544106Sbrian      cx->physical->link.lcp.cfg.chap05 |= add;
267636285Sbrian      break;
267744106Sbrian#ifdef HAVE_DES
267844106Sbrian    case NEG_CHAP80:
267944106Sbrian      cx->physical->link.lcp.cfg.chap80nt &= keep;
268044106Sbrian      cx->physical->link.lcp.cfg.chap80nt |= add;
268144106Sbrian      break;
268244106Sbrian    case NEG_CHAP80LM:
268344106Sbrian      cx->physical->link.lcp.cfg.chap80lm &= keep;
268444106Sbrian      cx->physical->link.lcp.cfg.chap80lm |= add;
268544106Sbrian      break;
268667910Sbrian    case NEG_CHAP81:
268767910Sbrian      cx->physical->link.lcp.cfg.chap81 &= keep;
268867910Sbrian      cx->physical->link.lcp.cfg.chap81 |= add;
268967910Sbrian      break;
269067910Sbrian    case NEG_MPPE:
269167910Sbrian      l->ccp.cfg.neg[CCP_NEG_MPPE] &= keep;
269267910Sbrian      l->ccp.cfg.neg[CCP_NEG_MPPE] |= add;
269367910Sbrian      break;
269444106Sbrian#endif
269536285Sbrian    case NEG_DEFLATE:
269636285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE] &= keep;
269736285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE] |= add;
269836285Sbrian      break;
269936285Sbrian    case NEG_DNS:
270036285Sbrian      arg->bundle->ncp.ipcp.cfg.ns.dns_neg &= keep;
270136285Sbrian      arg->bundle->ncp.ipcp.cfg.ns.dns_neg |= add;
270236285Sbrian      break;
270347858Sbrian    case NEG_ENDDISC:
270447858Sbrian      arg->bundle->ncp.mp.cfg.negenddisc &= keep;
270547858Sbrian      arg->bundle->ncp.mp.cfg.negenddisc |= add;
270647858Sbrian      break;
270736285Sbrian    case NEG_LQR:
270836285Sbrian      cx->physical->link.lcp.cfg.lqr &= keep;
270936285Sbrian      cx->physical->link.lcp.cfg.lqr |= add;
271036285Sbrian      break;
271136285Sbrian    case NEG_PAP:
271236285Sbrian      cx->physical->link.lcp.cfg.pap &= keep;
271336285Sbrian      cx->physical->link.lcp.cfg.pap |= add;
271436285Sbrian      break;
271536285Sbrian    case NEG_PPPDDEFLATE:
271636285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE24] &= keep;
271736285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE24] |= add;
271836285Sbrian      break;
271936285Sbrian    case NEG_PRED1:
272036285Sbrian      l->ccp.cfg.neg[CCP_NEG_PRED1] &= keep;
272136285Sbrian      l->ccp.cfg.neg[CCP_NEG_PRED1] |= add;
272236285Sbrian      break;
272336285Sbrian    case NEG_PROTOCOMP:
272436285Sbrian      cx->physical->link.lcp.cfg.protocomp &= keep;
272536285Sbrian      cx->physical->link.lcp.cfg.protocomp |= add;
272636285Sbrian      break;
272736285Sbrian    case NEG_SHORTSEQ:
272840622Sbrian      switch (bundle_Phase(arg->bundle)) {
272940622Sbrian        case PHASE_DEAD:
273040622Sbrian          break;
273140622Sbrian        case PHASE_ESTABLISH:
273240622Sbrian          /* Make sure none of our links are DATALINK_LCP or greater */
273340622Sbrian          if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) {
273440622Sbrian            log_Printf(LogWARN, "shortseq: Only changable before"
273540622Sbrian                       " LCP negotiations\n");
273640622Sbrian            return 1;
273740622Sbrian          }
273840622Sbrian          break;
273940622Sbrian        default:
274040622Sbrian          log_Printf(LogWARN, "shortseq: Only changable at phase"
274140622Sbrian                     " DEAD/ESTABLISH\n");
274240622Sbrian          return 1;
274336285Sbrian      }
274440622Sbrian      arg->bundle->ncp.mp.cfg.shortseq &= keep;
274540622Sbrian      arg->bundle->ncp.mp.cfg.shortseq |= add;
274636285Sbrian      break;
274736285Sbrian    case NEG_VJCOMP:
274836285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.neg &= keep;
274936285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.neg |= add;
275036285Sbrian      break;
275136285Sbrian  }
275236285Sbrian
275336285Sbrian  return 0;
275436285Sbrian}
275536285Sbrian
275636285Sbrianstatic struct cmdtab const NegotiateCommands[] = {
275762778Sbrian  {"filter-decapsulation", NULL, OptSet, LOCAL_AUTH,
275862778Sbrian  "filter on PPPoUDP payloads", "disable|enable",
275962778Sbrian  (const void *)OPT_FILTERDECAP},
276036285Sbrian  {"idcheck", NULL, OptSet, LOCAL_AUTH, "Check FSM reply ids",
276136285Sbrian  "disable|enable", (const void *)OPT_IDCHECK},
276240666Sbrian  {"iface-alias", NULL, IfaceAliasOptSet, LOCAL_AUTH,
276362778Sbrian  "retain interface addresses", "disable|enable",
276462778Sbrian  (const void *)OPT_IFACEALIAS},
276581634Sbrian#ifndef NOINET6
276681634Sbrian  {"ipcp", NULL, OptSet, LOCAL_AUTH, "IP Network Control Protocol",
276781634Sbrian  "disable|enable", (const void *)OPT_IPCP},
276881634Sbrian  {"ipv6cp", NULL, OptSet, LOCAL_AUTH, "IPv6 Network Control Protocol",
276981634Sbrian  "disable|enable", (const void *)OPT_IPV6CP},
277081634Sbrian#endif
277147689Sbrian  {"keep-session", NULL, OptSet, LOCAL_AUTH, "Retain device session leader",
277247689Sbrian  "disable|enable", (const void *)OPT_KEEPSESSION},
277336285Sbrian  {"loopback", NULL, OptSet, LOCAL_AUTH, "Loop packets for local iface",
277436285Sbrian  "disable|enable", (const void *)OPT_LOOPBACK},
277536285Sbrian  {"passwdauth", NULL, OptSet, LOCAL_AUTH, "Use passwd file",
277636285Sbrian  "disable|enable", (const void *)OPT_PASSWDAUTH},
277740665Sbrian  {"proxy", NULL, OptSet, LOCAL_AUTH, "Create a proxy ARP entry",
277836285Sbrian  "disable|enable", (const void *)OPT_PROXY},
277940665Sbrian  {"proxyall", NULL, OptSet, LOCAL_AUTH, "Proxy ARP for all remote hosts",
278040665Sbrian  "disable|enable", (const void *)OPT_PROXYALL},
278136285Sbrian  {"sroutes", NULL, OptSet, LOCAL_AUTH, "Use sticky routes",
278236285Sbrian  "disable|enable", (const void *)OPT_SROUTES},
278369303Sbrian  {"tcpmssfixup", "mssfixup", OptSet, LOCAL_AUTH, "Modify MSS options",
278469303Sbrian  "disable|enable", (const void *)OPT_TCPMSSFIXUP},
278536285Sbrian  {"throughput", NULL, OptSet, LOCAL_AUTH, "Rolling throughput",
278636285Sbrian  "disable|enable", (const void *)OPT_THROUGHPUT},
278736285Sbrian  {"utmp", NULL, OptSet, LOCAL_AUTH, "Log connections in utmp",
278836285Sbrian  "disable|enable", (const void *)OPT_UTMP},
278936285Sbrian
279081634Sbrian#ifndef NOINET6
279181634Sbrian#define OPT_MAX 13	/* accept/deny allowed below and not above */
279281634Sbrian#else
279381634Sbrian#define OPT_MAX 11
279481634Sbrian#endif
279536285Sbrian
279636285Sbrian  {"acfcomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
279736285Sbrian  "Address & Control field compression", "accept|deny|disable|enable",
279836285Sbrian  (const void *)NEG_ACFCOMP},
279944106Sbrian  {"chap", "chap05", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
280036285Sbrian  "Challenge Handshake Authentication Protocol", "accept|deny|disable|enable",
280144106Sbrian  (const void *)NEG_CHAP05},
280244106Sbrian#ifdef HAVE_DES
280344106Sbrian  {"mschap", "chap80nt", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
280444106Sbrian  "Microsoft (NT) CHAP", "accept|deny|disable|enable",
280544106Sbrian  (const void *)NEG_CHAP80},
280644106Sbrian  {"LANMan", "chap80lm", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
280744106Sbrian  "Microsoft (NT) CHAP", "accept|deny|disable|enable",
280844106Sbrian  (const void *)NEG_CHAP80LM},
280967910Sbrian  {"mschapv2", "chap81", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
281067910Sbrian  "Microsoft CHAP v2", "accept|deny|disable|enable",
281167910Sbrian  (const void *)NEG_CHAP81},
281267910Sbrian  {"mppe", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
281367910Sbrian  "MPPE encryption", "accept|deny|disable|enable",
281467910Sbrian  (const void *)NEG_MPPE},
281544106Sbrian#endif
281636285Sbrian  {"deflate", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
281736285Sbrian  "Deflate compression", "accept|deny|disable|enable",
281836285Sbrian  (const void *)NEG_DEFLATE},
281936285Sbrian  {"deflate24", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
282036285Sbrian  "Deflate (type 24) compression", "accept|deny|disable|enable",
282136285Sbrian  (const void *)NEG_PPPDDEFLATE},
282236285Sbrian  {"dns", NULL, NegotiateSet, LOCAL_AUTH,
282336285Sbrian  "DNS specification", "accept|deny|disable|enable", (const void *)NEG_DNS},
282447858Sbrian  {"enddisc", NULL, NegotiateSet, LOCAL_AUTH, "ENDDISC negotiation",
282547858Sbrian  "accept|deny|disable|enable", (const void *)NEG_ENDDISC},
282636285Sbrian  {"lqr", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
282736285Sbrian  "Link Quality Reports", "accept|deny|disable|enable",
282836285Sbrian  (const void *)NEG_LQR},
282936285Sbrian  {"pap", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
283036285Sbrian  "Password Authentication protocol", "accept|deny|disable|enable",
283136285Sbrian  (const void *)NEG_PAP},
283236285Sbrian  {"pred1", "predictor1", NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
283336285Sbrian  "Predictor 1 compression", "accept|deny|disable|enable",
283436285Sbrian  (const void *)NEG_PRED1},
283536285Sbrian  {"protocomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
283636285Sbrian  "Protocol field compression", "accept|deny|disable|enable",
283736285Sbrian  (const void *)NEG_PROTOCOMP},
283836285Sbrian  {"shortseq", NULL, NegotiateSet, LOCAL_AUTH,
283936285Sbrian  "MP Short Sequence Numbers", "accept|deny|disable|enable",
284036285Sbrian  (const void *)NEG_SHORTSEQ},
284136285Sbrian  {"vjcomp", NULL, NegotiateSet, LOCAL_AUTH,
284236285Sbrian  "Van Jacobson header compression", "accept|deny|disable|enable",
284336285Sbrian  (const void *)NEG_VJCOMP},
284436285Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
284536285Sbrian  "Display this message", "accept|deny|disable|enable help|? [value]",
284636285Sbrian  NegotiateCommands},
284736285Sbrian  {NULL, NULL, NULL},
284836285Sbrian};
284936285Sbrian
285036285Sbrianstatic int
285136285SbrianNegotiateCommand(struct cmdargs const *arg)
285236285Sbrian{
285336285Sbrian  if (arg->argc > arg->argn) {
285436285Sbrian    char const *argv[3];
285536285Sbrian    unsigned keep, add;
285636285Sbrian    int n;
285736285Sbrian
285836285Sbrian    if ((argv[0] = ident_cmd(arg->argv[arg->argn-1], &keep, &add)) == NULL)
285936285Sbrian      return -1;
286036285Sbrian    argv[2] = NULL;
286136285Sbrian
286236285Sbrian    for (n = arg->argn; n < arg->argc; n++) {
286336285Sbrian      argv[1] = arg->argv[n];
286436285Sbrian      FindExec(arg->bundle, NegotiateCommands + (keep == NEG_HISMASK ?
286536285Sbrian               0 : OPT_MAX), 2, 1, argv, arg->prompt, arg->cx);
286636285Sbrian    }
286736285Sbrian  } else if (arg->prompt)
286836285Sbrian    prompt_Printf(arg->prompt, "Use `%s ?' to get a list.\n",
286936285Sbrian	    arg->argv[arg->argn-1]);
287036285Sbrian  else
287136285Sbrian    log_Printf(LogWARN, "%s command must have arguments\n",
287236285Sbrian              arg->argv[arg->argn] );
287336285Sbrian
287436285Sbrian  return 0;
287536285Sbrian}
287636285Sbrian
287736285Sbrianconst char *
287836285Sbriancommand_ShowNegval(unsigned val)
287936285Sbrian{
288036285Sbrian  switch (val&3) {
288136285Sbrian    case 1: return "disabled & accepted";
288236285Sbrian    case 2: return "enabled & denied";
288336285Sbrian    case 3: return "enabled & accepted";
288436285Sbrian  }
288536285Sbrian  return "disabled & denied";
288636285Sbrian}
288736934Sbrian
288836934Sbrianstatic int
288936934SbrianClearCommand(struct cmdargs const *arg)
289036934Sbrian{
289136934Sbrian  struct pppThroughput *t;
289236934Sbrian  struct datalink *cx;
289336934Sbrian  int i, clear_type;
289436934Sbrian
289536934Sbrian  if (arg->argc < arg->argn + 1)
289636934Sbrian    return -1;
289736934Sbrian
289846686Sbrian  if (strcasecmp(arg->argv[arg->argn], "physical") == 0) {
289936934Sbrian    cx = arg->cx;
290036934Sbrian    if (!cx)
290136934Sbrian      cx = bundle2datalink(arg->bundle, NULL);
290236934Sbrian    if (!cx) {
290346686Sbrian      log_Printf(LogWARN, "A link must be specified for ``clear physical''\n");
290436934Sbrian      return 1;
290536934Sbrian    }
290664652Sbrian    t = &cx->physical->link.stats.total;
290736934Sbrian  } else if (strcasecmp(arg->argv[arg->argn], "ipcp") == 0)
290836934Sbrian    t = &arg->bundle->ncp.ipcp.throughput;
290981634Sbrian#ifndef NOINET6
291081897Sbrian  else if (strcasecmp(arg->argv[arg->argn], "ipv6cp") == 0)
291181634Sbrian    t = &arg->bundle->ncp.ipv6cp.throughput;
291281634Sbrian#endif
291336934Sbrian  else
291436934Sbrian    return -1;
291536934Sbrian
291636934Sbrian  if (arg->argc > arg->argn + 1) {
291736934Sbrian    clear_type = 0;
291836934Sbrian    for (i = arg->argn + 1; i < arg->argc; i++)
291936934Sbrian      if (strcasecmp(arg->argv[i], "overall") == 0)
292036934Sbrian        clear_type |= THROUGHPUT_OVERALL;
292136934Sbrian      else if (strcasecmp(arg->argv[i], "current") == 0)
292236934Sbrian        clear_type |= THROUGHPUT_CURRENT;
292336934Sbrian      else if (strcasecmp(arg->argv[i], "peak") == 0)
292436934Sbrian        clear_type |= THROUGHPUT_PEAK;
292536934Sbrian      else
292636934Sbrian        return -1;
292736934Sbrian  } else
292836934Sbrian    clear_type = THROUGHPUT_ALL;
292936934Sbrian
293036934Sbrian  throughput_clear(t, clear_type, arg->prompt);
293136934Sbrian  return 0;
293236934Sbrian}
293340561Sbrian
293440561Sbrianstatic int
293540561SbrianRunListCommand(struct cmdargs const *arg)
293640561Sbrian{
293740561Sbrian  const char *cmd = arg->argc ? arg->argv[arg->argc - 1] : "???";
293840561Sbrian
293964801Sbrian#ifndef NONAT
294064801Sbrian  if (arg->cmd->args == NatCommands &&
294164801Sbrian      tolower(*arg->argv[arg->argn - 1]) == 'a') {
294264801Sbrian    if (arg->prompt)
294365550Sbrian      prompt_Printf(arg->prompt, "The alias command is deprecated\n");
294464801Sbrian    else
294565550Sbrian      log_Printf(LogWARN, "The alias command is deprecated\n");
294664801Sbrian  }
294764801Sbrian#endif
294864801Sbrian
294940561Sbrian  if (arg->argc > arg->argn)
295040561Sbrian    FindExec(arg->bundle, arg->cmd->args, arg->argc, arg->argn, arg->argv,
295140561Sbrian             arg->prompt, arg->cx);
295240561Sbrian  else if (arg->prompt)
295340561Sbrian    prompt_Printf(arg->prompt, "Use `%s help' to get a list or `%s help"
295440561Sbrian                  " <option>' for syntax help.\n", cmd, cmd);
295540561Sbrian  else
295640561Sbrian    log_Printf(LogWARN, "%s command must have arguments\n", cmd);
295740561Sbrian
295840561Sbrian  return 0;
295940561Sbrian}
296040561Sbrian
296140561Sbrianstatic int
296240561SbrianIfaceAddCommand(struct cmdargs const *arg)
296340561Sbrian{
296481634Sbrian  struct ncpaddr peer, addr;
296581634Sbrian  struct ncprange ifa;
296681634Sbrian  struct in_addr mask;
296781634Sbrian  int n, how;
296840561Sbrian
296940664Sbrian  if (arg->argc == arg->argn + 1) {
297081634Sbrian    if (!ncprange_aton(&ifa, NULL, arg->argv[arg->argn]))
297140561Sbrian      return -1;
297281634Sbrian    ncpaddr_init(&peer);
297340664Sbrian  } else {
297440664Sbrian    if (arg->argc == arg->argn + 2) {
297581634Sbrian      if (!ncprange_aton(&ifa, NULL, arg->argv[arg->argn]))
297640664Sbrian        return -1;
297740664Sbrian      n = 1;
297840664Sbrian    } else if (arg->argc == arg->argn + 3) {
297981634Sbrian      if (!ncpaddr_aton(&addr, NULL, arg->argv[arg->argn]))
298040664Sbrian        return -1;
298181634Sbrian      if (ncpaddr_family(&addr) != AF_INET)
298240664Sbrian        return -1;
298381634Sbrian      ncprange_sethost(&ifa, &addr);
298481634Sbrian      if (!ncpaddr_aton(&addr, NULL, arg->argv[arg->argn + 1]))
298581634Sbrian        return -1;
298681634Sbrian      if (!ncpaddr_getip4(&addr, &mask))
298781634Sbrian        return -1;
298881634Sbrian      if (!ncprange_setip4mask(&ifa, mask))
298981634Sbrian        return -1;
299040664Sbrian      n = 2;
299140664Sbrian    } else
299240561Sbrian      return -1;
299340561Sbrian
299481634Sbrian    if (!ncpaddr_aton(&peer, NULL, arg->argv[arg->argn + n]))
299540664Sbrian      return -1;
299681634Sbrian
299781634Sbrian    if (ncprange_family(&ifa) != ncpaddr_family(&peer)) {
299881634Sbrian      log_Printf(LogWARN, "IfaceAddCommand: src and dst address families"
299981634Sbrian                 " differ\n");
300081634Sbrian      return -1;
300181634Sbrian    }
300240664Sbrian  }
300340561Sbrian
300440561Sbrian  how = IFACE_ADD_LAST;
300540561Sbrian  if (arg->cmd->args)
300640561Sbrian    how |= IFACE_FORCE_ADD;
300740561Sbrian
300881634Sbrian  return !iface_Add(arg->bundle->iface, &arg->bundle->ncp, &ifa, &peer, how);
300940561Sbrian}
301040561Sbrian
301140561Sbrianstatic int
301240561SbrianIfaceDeleteCommand(struct cmdargs const *arg)
301340561Sbrian{
301481634Sbrian  struct ncpaddr ifa;
301581634Sbrian  struct in_addr ifa4;
301640561Sbrian  int ok;
301740561Sbrian
301840561Sbrian  if (arg->argc != arg->argn + 1)
301940561Sbrian    return -1;
302040561Sbrian
302181634Sbrian  if (!ncpaddr_aton(&ifa, NULL, arg->argv[arg->argn]))
302240561Sbrian    return -1;
302340561Sbrian
302440561Sbrian  if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED &&
302581634Sbrian      ncpaddr_getip4(&ifa, &ifa4) &&
302681634Sbrian      arg->bundle->ncp.ipcp.my_ip.s_addr == ifa4.s_addr) {
302740561Sbrian    log_Printf(LogWARN, "%s: Cannot remove active interface address\n",
302881634Sbrian               ncpaddr_ntoa(&ifa));
302940561Sbrian    return 1;
303040561Sbrian  }
303140561Sbrian
303281634Sbrian  ok = iface_Delete(arg->bundle->iface, &arg->bundle->ncp, &ifa);
303340561Sbrian  if (!ok) {
303440561Sbrian    if (arg->cmd->args)
303540561Sbrian      ok = 1;
303640561Sbrian    else if (arg->prompt)
303781634Sbrian      prompt_Printf(arg->prompt, "%s: No such interface address\n",
303881634Sbrian                    ncpaddr_ntoa(&ifa));
303940561Sbrian    else
304081634Sbrian      log_Printf(LogWARN, "%s: No such interface address\n",
304181634Sbrian                 ncpaddr_ntoa(&ifa));
304240561Sbrian  }
304340561Sbrian
304440561Sbrian  return !ok;
304540561Sbrian}
304640561Sbrian
304740561Sbrianstatic int
304840561SbrianIfaceClearCommand(struct cmdargs const *arg)
304940561Sbrian{
305081634Sbrian  int family, how;
305140561Sbrian
305281634Sbrian  family = 0;
305381634Sbrian  if (arg->argc == arg->argn + 1) {
305481634Sbrian    if (strcasecmp(arg->argv[arg->argn], "inet") == 0)
305581634Sbrian      family = AF_INET;
305681634Sbrian#ifndef NOINET6
305781897Sbrian    else if (strcasecmp(arg->argv[arg->argn], "inet6") == 0)
305881634Sbrian      family = AF_INET6;
305981634Sbrian#endif
306081634Sbrian    else
306181634Sbrian      return -1;
306281634Sbrian  } else if (arg->argc != arg->argn)
306340561Sbrian    return -1;
306440561Sbrian
306540941Sbrian  how = arg->bundle->ncp.ipcp.fsm.state == ST_OPENED ||
306640941Sbrian        arg->bundle->phys_type.all & PHYS_AUTO ?
306740561Sbrian        IFACE_CLEAR_ALIASES : IFACE_CLEAR_ALL;
306881634Sbrian  iface_Clear(arg->bundle->iface, &arg->bundle->ncp, family, how);
306940561Sbrian
307040561Sbrian  return 0;
307140561Sbrian}
307240679Sbrian
307340679Sbrianstatic int
307440679SbrianSetProcTitle(struct cmdargs const *arg)
307540679Sbrian{
307640679Sbrian  static char title[LINE_LEN];
307786028Sbrian  char *argv[MAXARGS];
307886028Sbrian  int argc = arg->argc - arg->argn;
307940679Sbrian
308040679Sbrian  if (arg->argc == arg->argn) {
308164698Sbrian    SetTitle(NULL);
308240679Sbrian    return 0;
308340679Sbrian  }
308440679Sbrian
308540679Sbrian  if (argc >= sizeof argv / sizeof argv[0]) {
308640679Sbrian    argc = sizeof argv / sizeof argv[0] - 1;
308740679Sbrian    log_Printf(LogWARN, "Truncating proc title to %d args\n", argc);
308840679Sbrian  }
308947849Sbrian  command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 1, getpid());
309085991Sbrian  Concatinate(title, sizeof title, argc, (const char *const *)argv);
309164698Sbrian  SetTitle(title);
309285991Sbrian  command_Free(argc, argv);
309340679Sbrian
309440679Sbrian  return 0;
309540679Sbrian}
3096