command.c revision 120372
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 120372 2003-09-23 07:41:55Z marcus $
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>
45102500Sbrian#include <stdarg.h>
4630715Sbrian#include <stdio.h>
4730715Sbrian#include <stdlib.h>
4830715Sbrian#include <string.h>
4930715Sbrian#include <sys/wait.h>
5030715Sbrian#include <termios.h>
5130715Sbrian#include <unistd.h>
5230715Sbrian
5350059Sbrian#ifndef NONAT
5458037Sbrian#ifdef LOCALNAT
5558037Sbrian#include "alias.h"
5658037Sbrian#else
5746086Sbrian#include <alias.h>
5839395Sbrian#endif
5939395Sbrian#endif
6058037Sbrian
6146686Sbrian#include "layer.h"
6237009Sbrian#include "defs.h"
6331343Sbrian#include "command.h"
6430715Sbrian#include "mbuf.h"
6530715Sbrian#include "log.h"
6630715Sbrian#include "timer.h"
676059Samurai#include "fsm.h"
6831690Sbrian#include "iplist.h"
6936285Sbrian#include "throughput.h"
7036285Sbrian#include "slcompress.h"
7138557Sbrian#include "lqr.h"
7238557Sbrian#include "hdlc.h"
7363484Sbrian#include "lcp.h"
7481634Sbrian#include "ncpaddr.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
144102558Sbrian#define	VAR_IPV6CPRETRY	37
1456059Samurai
14636285Sbrian/* ``accept|deny|disable|enable'' masks */
14736285Sbrian#define NEG_HISMASK (1)
14836285Sbrian#define NEG_MYMASK (2)
14936285Sbrian
15036285Sbrian/* ``accept|deny|disable|enable'' values */
15136285Sbrian#define NEG_ACFCOMP	40
15244106Sbrian#define NEG_CHAP05	41
15344106Sbrian#define NEG_CHAP80	42
15444106Sbrian#define NEG_CHAP80LM	43
15544106Sbrian#define NEG_DEFLATE	44
15647858Sbrian#define NEG_DNS		45
15747858Sbrian#define NEG_ENDDISC	46
15847858Sbrian#define NEG_LQR		47
15947858Sbrian#define NEG_PAP		48
16047858Sbrian#define NEG_PPPDDEFLATE	49
16147858Sbrian#define NEG_PRED1	50
16247858Sbrian#define NEG_PROTOCOMP	51
16347858Sbrian#define NEG_SHORTSEQ	52
16447858Sbrian#define NEG_VJCOMP	53
16567910Sbrian#define NEG_MPPE	54
16667910Sbrian#define NEG_CHAP81	55
16736285Sbrian
16898150Sbrianconst char Version[] = "3.1";
16936285Sbrian
17036285Sbrianstatic int ShowCommand(struct cmdargs const *);
17136285Sbrianstatic int TerminalCommand(struct cmdargs const *);
17236285Sbrianstatic int QuitCommand(struct cmdargs const *);
17336285Sbrianstatic int OpenCommand(struct cmdargs const *);
17436285Sbrianstatic int CloseCommand(struct cmdargs const *);
17536285Sbrianstatic int DownCommand(struct cmdargs const *);
17636285Sbrianstatic int SetCommand(struct cmdargs const *);
17736285Sbrianstatic int LinkCommand(struct cmdargs const *);
17836285Sbrianstatic int AddCommand(struct cmdargs const *);
17936285Sbrianstatic int DeleteCommand(struct cmdargs const *);
18036285Sbrianstatic int NegotiateCommand(struct cmdargs const *);
18136934Sbrianstatic int ClearCommand(struct cmdargs const *);
18240561Sbrianstatic int RunListCommand(struct cmdargs const *);
18340561Sbrianstatic int IfaceAddCommand(struct cmdargs const *);
18440561Sbrianstatic int IfaceDeleteCommand(struct cmdargs const *);
18540561Sbrianstatic int IfaceClearCommand(struct cmdargs const *);
18640679Sbrianstatic int SetProcTitle(struct cmdargs const *);
18750059Sbrian#ifndef NONAT
18858867Sbrianstatic int NatEnable(struct cmdargs const *);
18958867Sbrianstatic int NatOption(struct cmdargs const *);
19031343Sbrian#endif
1916059Samurai
19236285Sbrianstatic const char *
19336285Sbrianshowcx(struct cmdtab const *cmd)
19436285Sbrian{
19536285Sbrian  if (cmd->lauth & LOCAL_CX)
19636285Sbrian    return "(c)";
19736285Sbrian  else if (cmd->lauth & LOCAL_CX_OPT)
19836285Sbrian    return "(o)";
19936285Sbrian
20036285Sbrian  return "";
20136285Sbrian}
20236285Sbrian
2036059Samuraistatic int
20431343SbrianHelpCommand(struct cmdargs const *arg)
2056059Samurai{
20628679Sbrian  struct cmdtab const *cmd;
20736285Sbrian  int n, cmax, dmax, cols, cxlen;
20836285Sbrian  const char *cx;
2096059Samurai
21036285Sbrian  if (!arg->prompt) {
21136285Sbrian    log_Printf(LogWARN, "help: Cannot help without a prompt\n");
21226516Sbrian    return 0;
21336285Sbrian  }
21426516Sbrian
21536285Sbrian  if (arg->argc > arg->argn) {
21636285Sbrian    for (cmd = arg->cmdtab; cmd->name || cmd->alias; cmd++)
21736285Sbrian      if ((cmd->lauth & arg->prompt->auth) &&
21836285Sbrian          ((cmd->name && !strcasecmp(cmd->name, arg->argv[arg->argn])) ||
21936285Sbrian           (cmd->alias && !strcasecmp(cmd->alias, arg->argv[arg->argn])))) {
22036285Sbrian	prompt_Printf(arg->prompt, "%s %s\n", cmd->syntax, showcx(cmd));
22128679Sbrian	return 0;
2226059Samurai      }
22326516Sbrian    return -1;
2246059Samurai  }
22536285Sbrian
22631372Sbrian  cmax = dmax = 0;
22736285Sbrian  for (cmd = arg->cmdtab; cmd->func; cmd++)
22836285Sbrian    if (cmd->name && (cmd->lauth & arg->prompt->auth)) {
22936285Sbrian      if ((n = strlen(cmd->name) + strlen(showcx(cmd))) > cmax)
23031372Sbrian        cmax = n;
23131372Sbrian      if ((n = strlen(cmd->helpmes)) > dmax)
23231372Sbrian        dmax = n;
23331372Sbrian    }
23431372Sbrian
23531372Sbrian  cols = 80 / (dmax + cmax + 3);
2366059Samurai  n = 0;
23736285Sbrian  prompt_Printf(arg->prompt, "(o) = Optional context,"
23836285Sbrian                " (c) = Context required\n");
23936285Sbrian  for (cmd = arg->cmdtab; cmd->func; cmd++)
24036285Sbrian    if (cmd->name && (cmd->lauth & arg->prompt->auth)) {
24136285Sbrian      cx = showcx(cmd);
24236285Sbrian      cxlen = cmax - strlen(cmd->name);
24340482Sbrian      if (n % cols != 0)
24440482Sbrian        prompt_Printf(arg->prompt, " ");
24540482Sbrian      prompt_Printf(arg->prompt, "%s%-*.*s: %-*.*s",
24636285Sbrian              cmd->name, cxlen, cxlen, cx, dmax, dmax, cmd->helpmes);
24731372Sbrian      if (++n % cols == 0)
24836285Sbrian        prompt_Printf(arg->prompt, "\n");
2496059Samurai    }
25031372Sbrian  if (n % cols != 0)
25136285Sbrian    prompt_Printf(arg->prompt, "\n");
25226516Sbrian
25326516Sbrian  return 0;
2546059Samurai}
2556059Samurai
25636285Sbrianstatic int
25763484SbrianIdentCommand(struct cmdargs const *arg)
25863484Sbrian{
25985991Sbrian  Concatinate(arg->cx->physical->link.lcp.cfg.ident,
26085991Sbrian              sizeof arg->cx->physical->link.lcp.cfg.ident,
26185991Sbrian              arg->argc - arg->argn, arg->argv + arg->argn);
26263484Sbrian  return 0;
26363484Sbrian}
26463484Sbrian
26563484Sbrianstatic int
26663484SbrianSendIdentification(struct cmdargs const *arg)
26763484Sbrian{
26863484Sbrian  if (arg->cx->state < DATALINK_LCP) {
26963484Sbrian    log_Printf(LogWARN, "sendident: link has not reached LCP\n");
27063484Sbrian    return 2;
27163484Sbrian  }
27263484Sbrian  return lcp_SendIdentification(&arg->cx->physical->link.lcp) ? 0 : 1;
27363484Sbrian}
27463484Sbrian
27563484Sbrianstatic int
27636285SbrianCloneCommand(struct cmdargs const *arg)
2776059Samurai{
27836285Sbrian  char namelist[LINE_LEN];
27936285Sbrian  char *name;
28036285Sbrian  int f;
2816059Samurai
28236285Sbrian  if (arg->argc == arg->argn)
28336285Sbrian    return -1;
28436285Sbrian
28536285Sbrian  namelist[sizeof namelist - 1] = '\0';
28636285Sbrian  for (f = arg->argn; f < arg->argc; f++) {
28736285Sbrian    strncpy(namelist, arg->argv[f], sizeof namelist - 1);
28836285Sbrian    for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
28936285Sbrian      bundle_DatalinkClone(arg->bundle, arg->cx, name);
2906059Samurai  }
29136285Sbrian
29236285Sbrian  return 0;
2936059Samurai}
2946059Samurai
2956059Samuraistatic int
29636285SbrianRemoveCommand(struct cmdargs const *arg)
2976059Samurai{
29836285Sbrian  if (arg->argc != arg->argn)
29936285Sbrian    return -1;
30011336Samurai
30136285Sbrian  if (arg->cx->state != DATALINK_CLOSED) {
30236285Sbrian    log_Printf(LogWARN, "remove: Cannot delete links that aren't closed\n");
30336285Sbrian    return 2;
3046059Samurai  }
30526516Sbrian
30636285Sbrian  bundle_DatalinkRemove(arg->bundle, arg->cx);
30736285Sbrian  return 0;
30836285Sbrian}
30932711Sbrian
31036285Sbrianstatic int
31136285SbrianRenameCommand(struct cmdargs const *arg)
31236285Sbrian{
31336285Sbrian  if (arg->argc != arg->argn + 1)
31436285Sbrian    return -1;
31531121Sbrian
31636285Sbrian  if (bundle_RenameDatalink(arg->bundle, arg->cx, arg->argv[arg->argn]))
31736285Sbrian    return 0;
31836285Sbrian
31998243Sbrian  log_Printf(LogWARN, "%s -> %s: target name already exists\n",
32036285Sbrian             arg->cx->name, arg->argv[arg->argn]);
32136285Sbrian  return 1;
32236285Sbrian}
32336285Sbrian
32485991Sbrianstatic int
32536285SbrianLoadCommand(struct cmdargs const *arg)
32636285Sbrian{
32740797Sbrian  const char *err;
32840797Sbrian  int n, mode;
32936285Sbrian
33040797Sbrian  mode = arg->bundle->phys_type.all;
33136285Sbrian
33240797Sbrian  if (arg->argn < arg->argc) {
33340797Sbrian    for (n = arg->argn; n < arg->argc; n++)
33440797Sbrian      if ((err = system_IsValid(arg->argv[n], arg->prompt, mode)) != NULL) {
33540797Sbrian        log_Printf(LogWARN, "%s: %s\n", arg->argv[n], err);
33640797Sbrian        return 1;
33740797Sbrian      }
33840797Sbrian
33940797Sbrian    for (n = arg->argn; n < arg->argc; n++) {
34040797Sbrian      bundle_SetLabel(arg->bundle, arg->argv[arg->argc - 1]);
34140797Sbrian      system_Select(arg->bundle, arg->argv[n], CONFFILE, arg->prompt, arg->cx);
34240797Sbrian    }
34340797Sbrian    bundle_SetLabel(arg->bundle, arg->argv[arg->argc - 1]);
34440797Sbrian  } else if ((err = system_IsValid("default", arg->prompt, mode)) != NULL) {
34540797Sbrian    log_Printf(LogWARN, "default: %s\n", err);
34636285Sbrian    return 1;
34736285Sbrian  } else {
34840797Sbrian    bundle_SetLabel(arg->bundle, "default");
34940797Sbrian    system_Select(arg->bundle, "default", CONFFILE, arg->prompt, arg->cx);
35040797Sbrian    bundle_SetLabel(arg->bundle, "default");
35136285Sbrian  }
35240797Sbrian
35326516Sbrian  return 0;
3546059Samurai}
3556059Samurai
35685991Sbrianstatic int
35785991SbrianLogCommand(struct cmdargs const *arg)
35885991Sbrian{
35985991Sbrian  char buf[LINE_LEN];
36085991Sbrian
36185991Sbrian  if (arg->argn < arg->argc) {
36285991Sbrian    char *argv[MAXARGS];
36385991Sbrian    int argc = arg->argc - arg->argn;
36485991Sbrian
36585991Sbrian    if (argc >= sizeof argv / sizeof argv[0]) {
36685991Sbrian      argc = sizeof argv / sizeof argv[0] - 1;
36785991Sbrian      log_Printf(LogWARN, "Truncating log command to %d args\n", argc);
36885991Sbrian    }
36986760Sbrian    command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 1, getpid());
37085991Sbrian    Concatinate(buf, sizeof buf, argc, (const char *const *)argv);
37185991Sbrian    log_Printf(LogLOG, "%s\n", buf);
37285991Sbrian    command_Free(argc, argv);
37385991Sbrian    return 0;
37485991Sbrian  }
37585991Sbrian
37685991Sbrian  return -1;
37785991Sbrian}
37885991Sbrian
37985991Sbrianstatic int
38036285SbrianSaveCommand(struct cmdargs const *arg)
38136285Sbrian{
38285991Sbrian  log_Printf(LogWARN, "save command is not yet implemented.\n");
38336285Sbrian  return 1;
38436285Sbrian}
38536285Sbrian
38610528Samuraistatic int
38736285SbrianDialCommand(struct cmdargs const *arg)
38828536Sbrian{
38936285Sbrian  int res;
39036285Sbrian
39136465Sbrian  if ((arg->cx && !(arg->cx->physical->type & (PHYS_INTERACTIVE|PHYS_AUTO)))
39236465Sbrian      || (!arg->cx &&
39336928Sbrian          (arg->bundle->phys_type.all & ~(PHYS_INTERACTIVE|PHYS_AUTO)))) {
39436285Sbrian    log_Printf(LogWARN, "Manual dial is only available for auto and"
39536285Sbrian              " interactive links\n");
39636285Sbrian    return 1;
39734536Sbrian  }
39836285Sbrian
39936285Sbrian  if (arg->argc > arg->argn && (res = LoadCommand(arg)) != 0)
40036285Sbrian    return res;
40136285Sbrian
40237993Sbrian  bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1);
40336285Sbrian
40436285Sbrian  return 0;
40528536Sbrian}
40628536Sbrian
40738628Sbrian#define isinword(ch) (isalnum(ch) || (ch) == '_')
40838628Sbrian
40938628Sbrianstatic char *
41038628Sbrianstrstrword(char *big, const char *little)
41138628Sbrian{
41238628Sbrian  /* Get the first occurance of the word ``little'' in ``big'' */
41338628Sbrian  char *pos;
41438628Sbrian  int len;
41538628Sbrian
41638628Sbrian  pos = big;
41738628Sbrian  len = strlen(little);
41838628Sbrian
41938628Sbrian  while ((pos = strstr(pos, little)) != NULL)
42047865Sbrian    if ((pos != big && isinword(pos[-1])) || isinword(pos[len]))
42147865Sbrian      pos++;
42247865Sbrian    else if (pos != big && pos[-1] == '\\')
42347865Sbrian      memmove(pos - 1, pos, strlen(pos) + 1);
42447865Sbrian    else
42538628Sbrian      break;
42638628Sbrian
42738628Sbrian  return pos;
42838628Sbrian}
42938628Sbrian
43038628Sbrianstatic char *
43138628Sbriansubst(char *tgt, const char *oldstr, const char *newstr)
43238628Sbrian{
43338628Sbrian  /* tgt is a malloc()d area... realloc() as necessary */
43438628Sbrian  char *word, *ntgt;
43538628Sbrian  int ltgt, loldstr, lnewstr, pos;
43638628Sbrian
43738628Sbrian  if ((word = strstrword(tgt, oldstr)) == NULL)
43838628Sbrian    return tgt;
43938628Sbrian
44038628Sbrian  ltgt = strlen(tgt) + 1;
44138628Sbrian  loldstr = strlen(oldstr);
44238628Sbrian  lnewstr = strlen(newstr);
44338628Sbrian  do {
44438628Sbrian    pos = word - tgt;
44538628Sbrian    if (loldstr > lnewstr)
44638628Sbrian      bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr);
44738628Sbrian    if (loldstr != lnewstr) {
44838628Sbrian      ntgt = realloc(tgt, ltgt += lnewstr - loldstr);
44938628Sbrian      if (ntgt == NULL)
45038628Sbrian        break;			/* Oh wonderful ! */
45138628Sbrian      word = ntgt + pos;
45238628Sbrian      tgt = ntgt;
45338628Sbrian    }
45438628Sbrian    if (lnewstr > loldstr)
45538628Sbrian      bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr);
45638628Sbrian    bcopy(newstr, word, lnewstr);
45738628Sbrian  } while ((word = strstrword(word, oldstr)));
45838628Sbrian
45938628Sbrian  return tgt;
46038628Sbrian}
46138628Sbrian
46294934Sbrianstatic char *
46394934Sbriansubstip(char *tgt, const char *oldstr, struct in_addr ip)
46494934Sbrian{
46594934Sbrian  return subst(tgt, oldstr, inet_ntoa(ip));
46694934Sbrian}
46794934Sbrian
46894934Sbrianstatic char *
46997360Sbriansubstlong(char *tgt, const char *oldstr, long l)
47094934Sbrian{
47197360Sbrian  char buf[23];
47294934Sbrian
47397360Sbrian  snprintf(buf, sizeof buf, "%ld", l);
47494934Sbrian
47594934Sbrian  return subst(tgt, oldstr, buf);
47694934Sbrian}
47794934Sbrian
47894934Sbrianstatic char *
47994934Sbriansubstull(char *tgt, const char *oldstr, unsigned long long ull)
48094934Sbrian{
48194934Sbrian  char buf[21];
48294934Sbrian
48394934Sbrian  snprintf(buf, sizeof buf, "%llu", ull);
48494934Sbrian
48594934Sbrian  return subst(tgt, oldstr, buf);
48694934Sbrian}
48794934Sbrian
48894934Sbrian
48994934Sbrian#ifndef NOINET6
49094934Sbrianstatic char *
49194934Sbriansubstipv6(char *tgt, const char *oldstr, const struct ncpaddr *ip)
49294934Sbrian{
49394934Sbrian    return subst(tgt, oldstr, ncpaddr_ntoa(ip));
49494934Sbrian}
495116622Sume
496116622Sume#ifndef NORADIUS
497116622Sumestatic char *
498116622Sumesubstipv6prefix(char *tgt, const char *oldstr, const uint8_t *ipv6prefix)
499116622Sume{
500116622Sume  uint8_t ipv6addr[INET6_ADDRSTRLEN];
501116622Sume  uint8_t prefix[INET6_ADDRSTRLEN + sizeof("/128") - 1];
502116622Sume
503116622Sume  if (ipv6prefix) {
504116622Sume    inet_ntop(AF_INET6, &ipv6prefix[2], ipv6addr, sizeof(ipv6addr));
505116622Sume    snprintf(prefix, sizeof(prefix), "%s/%d", ipv6addr, ipv6prefix[1]);
506116622Sume  } else
507116622Sume    prefix[0] = '\0';
508116622Sume  return subst(tgt, oldstr, prefix);
509116622Sume}
51094934Sbrian#endif
511116622Sume#endif
51294934Sbrian
51343888Sbrianvoid
51443888Sbriancommand_Expand(char **nargv, int argc, char const *const *oargv,
51547849Sbrian               struct bundle *bundle, int inc0, pid_t pid)
51638628Sbrian{
51785991Sbrian  int arg, secs;
51894934Sbrian  char uptime[20];
51994934Sbrian  unsigned long long oin, oout, pin, pout;
52038628Sbrian
52141755Sbrian  if (inc0)
52241755Sbrian    arg = 0;		/* Start at arg 0 */
52341755Sbrian  else {
52441755Sbrian    nargv[0] = strdup(oargv[0]);
52541755Sbrian    arg = 1;
52641755Sbrian  }
52794934Sbrian
52894934Sbrian  secs = bundle_Uptime(bundle);
52994934Sbrian  snprintf(uptime, sizeof uptime, "%d:%02d:%02d",
53094934Sbrian           secs / 3600, (secs / 60) % 60, secs % 60);
53194934Sbrian  oin = bundle->ncp.ipcp.throughput.OctetsIn;
53294934Sbrian  oout = bundle->ncp.ipcp.throughput.OctetsOut;
53394934Sbrian  pin = bundle->ncp.ipcp.throughput.PacketsIn;
53494934Sbrian  pout = bundle->ncp.ipcp.throughput.PacketsOut;
53594934Sbrian#ifndef NOINET6
53694934Sbrian  oin += bundle->ncp.ipv6cp.throughput.OctetsIn;
53794934Sbrian  oout += bundle->ncp.ipv6cp.throughput.OctetsOut;
53894934Sbrian  pin += bundle->ncp.ipv6cp.throughput.PacketsIn;
53994934Sbrian  pout += bundle->ncp.ipv6cp.throughput.PacketsOut;
54094934Sbrian#endif
54194934Sbrian
54241755Sbrian  for (; arg < argc; arg++) {
54338629Sbrian    nargv[arg] = strdup(oargv[arg]);
54494934Sbrian    nargv[arg] = subst(nargv[arg], "AUTHNAME", bundle->cfg.auth.name);
54594934Sbrian    nargv[arg] = subst(nargv[arg], "COMPILATIONDATE", __DATE__);
54694934Sbrian    nargv[arg] = substip(nargv[arg], "DNS0", bundle->ncp.ipcp.ns.dns[0]);
54794934Sbrian    nargv[arg] = substip(nargv[arg], "DNS1", bundle->ncp.ipcp.ns.dns[1]);
54898243Sbrian    nargv[arg] = subst(nargv[arg], "ENDDISC",
54994934Sbrian                       mp_Enddisc(bundle->ncp.mp.cfg.enddisc.class,
55094934Sbrian                                  bundle->ncp.mp.cfg.enddisc.address,
55194934Sbrian                                  bundle->ncp.mp.cfg.enddisc.len));
55294934Sbrian    nargv[arg] = substip(nargv[arg], "HISADDR", bundle->ncp.ipcp.peer_ip);
55381634Sbrian#ifndef NOINET6
55494934Sbrian    nargv[arg] = substipv6(nargv[arg], "HISADDR6", &bundle->ncp.ipv6cp.hisaddr);
55581634Sbrian#endif
55640561Sbrian    nargv[arg] = subst(nargv[arg], "INTERFACE", bundle->iface->name);
55794934Sbrian    nargv[arg] = substull(nargv[arg], "IPOCTETSIN",
55894934Sbrian                          bundle->ncp.ipcp.throughput.OctetsIn);
55998243Sbrian    nargv[arg] = substull(nargv[arg], "IPOCTETSOUT",
56094934Sbrian                          bundle->ncp.ipcp.throughput.OctetsOut);
56198243Sbrian    nargv[arg] = substull(nargv[arg], "IPPACKETSIN",
56294934Sbrian                          bundle->ncp.ipcp.throughput.PacketsIn);
56398243Sbrian    nargv[arg] = substull(nargv[arg], "IPPACKETSOUT",
56494934Sbrian                          bundle->ncp.ipcp.throughput.PacketsOut);
56581634Sbrian#ifndef NOINET6
56698243Sbrian    nargv[arg] = substull(nargv[arg], "IPV6OCTETSIN",
56794934Sbrian                          bundle->ncp.ipv6cp.throughput.OctetsIn);
56898243Sbrian    nargv[arg] = substull(nargv[arg], "IPV6OCTETSOUT",
56994934Sbrian                          bundle->ncp.ipv6cp.throughput.OctetsOut);
57098243Sbrian    nargv[arg] = substull(nargv[arg], "IPV6PACKETSIN",
57194934Sbrian                          bundle->ncp.ipv6cp.throughput.PacketsIn);
57298243Sbrian    nargv[arg] = substull(nargv[arg], "IPV6PACKETSOUT",
57394934Sbrian                          bundle->ncp.ipv6cp.throughput.PacketsOut);
57481634Sbrian#endif
57594934Sbrian    nargv[arg] = subst(nargv[arg], "LABEL", bundle_GetLabel(bundle));
57694934Sbrian    nargv[arg] = substip(nargv[arg], "MYADDR", bundle->ncp.ipcp.my_ip);
57794934Sbrian#ifndef NOINET6
57894934Sbrian    nargv[arg] = substipv6(nargv[arg], "MYADDR6", &bundle->ncp.ipv6cp.myaddr);
579116622Sume#ifndef NORADIUS
580116622Sume    nargv[arg] = substipv6prefix(nargv[arg], "IPV6PREFIX",
581116622Sume				 bundle->radius.ipv6prefix);
58294934Sbrian#endif
583116622Sume#endif
58494934Sbrian    nargv[arg] = substull(nargv[arg], "OCTETSIN", oin);
58594934Sbrian    nargv[arg] = substull(nargv[arg], "OCTETSOUT", oout);
58694934Sbrian    nargv[arg] = substull(nargv[arg], "PACKETSIN", pin);
58794934Sbrian    nargv[arg] = substull(nargv[arg], "PACKETSOUT", pout);
58838629Sbrian    nargv[arg] = subst(nargv[arg], "PEER_ENDDISC",
58938629Sbrian                       mp_Enddisc(bundle->ncp.mp.peer.enddisc.class,
59038629Sbrian                                  bundle->ncp.mp.peer.enddisc.address,
59138629Sbrian                                  bundle->ncp.mp.peer.enddisc.len));
59297360Sbrian    nargv[arg] = substlong(nargv[arg], "PROCESSID", pid);
59394934Sbrian    if (server.cfg.port)
59497360Sbrian      nargv[arg] = substlong(nargv[arg], "SOCKNAME", server.cfg.port);
59594934Sbrian    else
59694934Sbrian      nargv[arg] = subst(nargv[arg], "SOCKNAME", server.cfg.sockname);
59794934Sbrian    nargv[arg] = subst(nargv[arg], "UPTIME", uptime);
59894934Sbrian    nargv[arg] = subst(nargv[arg], "USER", bundle->ncp.mp.peer.authname);
59963484Sbrian    nargv[arg] = subst(nargv[arg], "VERSION", Version);
60038628Sbrian  }
60138628Sbrian  nargv[arg] = NULL;
60238628Sbrian}
60338628Sbrian
60485991Sbrianvoid
60585991Sbriancommand_Free(int argc, char **argv)
60685991Sbrian{
60785991Sbrian  while (argc) {
60885991Sbrian    free(*argv);
60985991Sbrian    argc--;
61085991Sbrian    argv++;
61185991Sbrian  }
61285991Sbrian}
61385991Sbrian
61428536Sbrianstatic int
61531343SbrianShellCommand(struct cmdargs const *arg, int bg)
61610528Samurai{
61710528Samurai  const char *shell;
61847849Sbrian  pid_t shpid, pid;
61920813Sjkh
62018856Ssos#ifdef SHELL_ONLY_INTERACTIVELY
62126911Sbrian  /* we're only allowed to shell when we run ppp interactively */
62236285Sbrian  if (arg->prompt && arg->prompt->owner) {
62336285Sbrian    log_Printf(LogWARN, "Can't start a shell from a network connection\n");
62426516Sbrian    return 1;
62510528Samurai  }
62626911Sbrian#endif
62728679Sbrian
62836285Sbrian  if (arg->argc == arg->argn) {
62936285Sbrian    if (!arg->prompt) {
63036285Sbrian      log_Printf(LogWARN, "Can't start an interactive shell from"
63136285Sbrian                " a config file\n");
63228381Sbrian      return 1;
63336285Sbrian    } else if (arg->prompt->owner) {
63436285Sbrian      log_Printf(LogWARN, "Can't start an interactive shell from"
63536285Sbrian                " a socket connection\n");
63636285Sbrian      return 1;
63728381Sbrian    } else if (bg) {
63836285Sbrian      log_Printf(LogWARN, "Can only start an interactive shell in"
63928679Sbrian		" the foreground mode\n");
64028381Sbrian      return 1;
64128381Sbrian    }
64234536Sbrian  }
64334536Sbrian
64447849Sbrian  pid = getpid();
64528679Sbrian  if ((shpid = fork()) == 0) {
64636285Sbrian    int i, fd;
64718531Sbde
64836285Sbrian    if ((shell = getenv("SHELL")) == 0)
64936285Sbrian      shell = _PATH_BSHELL;
65032017Sbrian
65136285Sbrian    timer_TermService();
65236285Sbrian
65336285Sbrian    if (arg->prompt)
65436285Sbrian      fd = arg->prompt->fd_out;
65536285Sbrian    else if ((fd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
65636285Sbrian      log_Printf(LogALERT, "Failed to open %s: %s\n",
65736285Sbrian                _PATH_DEVNULL, strerror(errno));
65828679Sbrian      exit(1);
65928679Sbrian    }
66049976Sbrian    dup2(fd, STDIN_FILENO);
66149976Sbrian    dup2(fd, STDOUT_FILENO);
66249976Sbrian    dup2(fd, STDERR_FILENO);
66349976Sbrian    for (i = getdtablesize(); i > STDERR_FILENO; i--)
66449976Sbrian      fcntl(i, F_SETFD, 1);
66526516Sbrian
66664802Sbrian#ifndef NOSUID
66755252Sbrian    setuid(ID0realuid());
66864802Sbrian#endif
66936285Sbrian    if (arg->argc > arg->argn) {
67028679Sbrian      /* substitute pseudo args */
67138628Sbrian      char *argv[MAXARGS];
67238628Sbrian      int argc = arg->argc - arg->argn;
67338628Sbrian
67438628Sbrian      if (argc >= sizeof argv / sizeof argv[0]) {
67538628Sbrian        argc = sizeof argv / sizeof argv[0] - 1;
67638628Sbrian        log_Printf(LogWARN, "Truncating shell command to %d args\n", argc);
67731343Sbrian      }
67847849Sbrian      command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 0, pid);
67928679Sbrian      if (bg) {
68028679Sbrian	pid_t p;
68110528Samurai
68228679Sbrian	p = getpid();
68328679Sbrian	if (daemon(1, 1) == -1) {
68497360Sbrian	  log_Printf(LogERROR, "%ld: daemon: %s\n", (long)p, strerror(errno));
68528679Sbrian	  exit(1);
68628679Sbrian	}
68736285Sbrian      } else if (arg->prompt)
68836285Sbrian        printf("ppp: Pausing until %s finishes\n", arg->argv[arg->argn]);
68931343Sbrian      execvp(argv[0], argv);
69030316Sbrian    } else {
69136285Sbrian      if (arg->prompt)
69232017Sbrian        printf("ppp: Pausing until %s finishes\n", shell);
69336285Sbrian      prompt_TtyOldMode(arg->prompt);
69479450Sbrian      execl(shell, shell, (char *)NULL);
69530316Sbrian    }
69620813Sjkh
69740665Sbrian    log_Printf(LogWARN, "exec() of %s failed: %s\n",
69840665Sbrian              arg->argc > arg->argn ? arg->argv[arg->argn] : shell,
69940665Sbrian              strerror(errno));
70049976Sbrian    _exit(255);
70110528Samurai  }
70236285Sbrian
70397360Sbrian  if (shpid == (pid_t)-1)
70436285Sbrian    log_Printf(LogERROR, "Fork failed: %s\n", strerror(errno));
70536285Sbrian  else {
70610528Samurai    int status;
70731343Sbrian    waitpid(shpid, &status, 0);
70810528Samurai  }
70920813Sjkh
71036285Sbrian  if (arg->prompt && !arg->prompt->owner)
71136285Sbrian    prompt_TtyCommandMode(arg->prompt);
71220813Sjkh
71336285Sbrian  return 0;
71410528Samurai}
71510528Samurai
71631343Sbrianstatic int
71731343SbrianBgShellCommand(struct cmdargs const *arg)
71831343Sbrian{
71936285Sbrian  if (arg->argc == arg->argn)
72031343Sbrian    return -1;
72131343Sbrian  return ShellCommand(arg, 1);
72231343Sbrian}
72331343Sbrian
72431343Sbrianstatic int
72531343SbrianFgShellCommand(struct cmdargs const *arg)
72631343Sbrian{
72731343Sbrian  return ShellCommand(arg, 0);
72831343Sbrian}
72931343Sbrian
73058044Sbrianstatic int
73158044SbrianResolvCommand(struct cmdargs const *arg)
73258044Sbrian{
73358044Sbrian  if (arg->argc == arg->argn + 1) {
73458044Sbrian    if (!strcasecmp(arg->argv[arg->argn], "reload"))
73558044Sbrian      ipcp_LoadDNS(&arg->bundle->ncp.ipcp);
73658044Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "restore"))
73758044Sbrian      ipcp_RestoreDNS(&arg->bundle->ncp.ipcp);
73858044Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "rewrite"))
73958044Sbrian      ipcp_WriteDNS(&arg->bundle->ncp.ipcp);
74058044Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "readonly"))
74158044Sbrian      arg->bundle->ncp.ipcp.ns.writable = 0;
74258044Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "writable"))
74358044Sbrian      arg->bundle->ncp.ipcp.ns.writable = 1;
74458044Sbrian    else
74558044Sbrian      return -1;
74658044Sbrian
74758044Sbrian    return 0;
74858044Sbrian  }
74958044Sbrian
75058044Sbrian  return -1;
75158044Sbrian}
75258044Sbrian
75350059Sbrian#ifndef NONAT
75458867Sbrianstatic struct cmdtab const NatCommands[] =
75540561Sbrian{
75650059Sbrian  {"addr", NULL, nat_RedirectAddr, LOCAL_AUTH,
75750059Sbrian   "static address translation", "nat addr [addr_local addr_alias]"},
75858867Sbrian  {"deny_incoming", NULL, NatOption, LOCAL_AUTH,
75950059Sbrian   "stop incoming connections", "nat deny_incoming yes|no",
76040561Sbrian   (const void *) PKT_ALIAS_DENY_INCOMING},
76158867Sbrian  {"enable", NULL, NatEnable, LOCAL_AUTH,
76250059Sbrian   "enable NAT", "nat enable yes|no"},
76358867Sbrian  {"log", NULL, NatOption, LOCAL_AUTH,
76450059Sbrian   "log NAT link creation", "nat log yes|no",
76540561Sbrian   (const void *) PKT_ALIAS_LOG},
76650059Sbrian  {"port", NULL, nat_RedirectPort, LOCAL_AUTH, "port redirection",
76750059Sbrian   "nat port proto localaddr:port[-port] aliasport[-aliasport]"},
76879433Sbrian  {"proto", NULL, nat_RedirectProto, LOCAL_AUTH, "protocol redirection",
76979433Sbrian   "nat proto proto localIP [publicIP [remoteIP]]"},
77050059Sbrian  {"proxy", NULL, nat_ProxyRule, LOCAL_AUTH,
77150059Sbrian   "proxy control", "nat proxy server host[:port] ..."},
77281033Sbrian#ifndef NO_FW_PUNCH
77381033Sbrian  {"punch_fw", NULL, nat_PunchFW, LOCAL_AUTH,
77481033Sbrian   "firewall control", "nat punch_fw [base count]"},
77581033Sbrian#endif
776120372Smarcus  {"skinny_port", NULL, nat_SkinnyPort, LOCAL_AUTH,
777120372Smarcus   "TCP port used by Skinny Station protocol", "nat skinny_port [port]"},
77858867Sbrian  {"same_ports", NULL, NatOption, LOCAL_AUTH,
77950059Sbrian   "try to leave port numbers unchanged", "nat same_ports yes|no",
78040561Sbrian   (const void *) PKT_ALIAS_SAME_PORTS},
78158867Sbrian  {"target", NULL, nat_SetTarget, LOCAL_AUTH,
78258867Sbrian   "Default address for incoming connections", "nat target addr" },
78358867Sbrian  {"unregistered_only", NULL, NatOption, LOCAL_AUTH,
78450059Sbrian   "translate unregistered (private) IP address space only",
78550059Sbrian   "nat unregistered_only yes|no",
78640561Sbrian   (const void *) PKT_ALIAS_UNREGISTERED_ONLY},
78758867Sbrian  {"use_sockets", NULL, NatOption, LOCAL_AUTH,
78850059Sbrian   "allocate host sockets", "nat use_sockets yes|no",
78940561Sbrian   (const void *) PKT_ALIAS_USE_SOCKETS},
79040561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
79158867Sbrian   "Display this message", "nat help|? [command]", NatCommands},
79240561Sbrian  {NULL, NULL, NULL},
79340561Sbrian};
79440561Sbrian#endif
79540561Sbrian
79640561Sbrianstatic struct cmdtab const AllowCommands[] = {
79740561Sbrian  {"modes", "mode", AllowModes, LOCAL_AUTH,
79840561Sbrian  "Only allow certain ppp modes", "allow modes mode..."},
79940561Sbrian  {"users", "user", AllowUsers, LOCAL_AUTH,
80040561Sbrian  "Only allow ppp access to certain users", "allow users logname..."},
80140561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
80240561Sbrian  "Display this message", "allow help|? [command]", AllowCommands},
80340561Sbrian  {NULL, NULL, NULL},
80440561Sbrian};
80540561Sbrian
80640561Sbrianstatic struct cmdtab const IfaceCommands[] =
80740561Sbrian{
80840561Sbrian  {"add", NULL, IfaceAddCommand, LOCAL_AUTH,
80940561Sbrian   "Add iface address", "iface add addr[/bits| mask] peer", NULL},
81040561Sbrian  {NULL, "add!", IfaceAddCommand, LOCAL_AUTH,
81140561Sbrian   "Add or change an iface address", "iface add! addr[/bits| mask] peer",
81240561Sbrian   (void *)1},
81340561Sbrian  {"clear", NULL, IfaceClearCommand, LOCAL_AUTH,
81481634Sbrian   "Clear iface address(es)", "iface clear [INET | INET6]"},
81540561Sbrian  {"delete", "rm", IfaceDeleteCommand, LOCAL_AUTH,
81640561Sbrian   "Delete iface address", "iface delete addr", NULL},
81740561Sbrian  {NULL, "rm!", IfaceDeleteCommand, LOCAL_AUTH,
81840561Sbrian   "Delete iface address", "iface delete addr", (void *)1},
81940561Sbrian  {NULL, "delete!", IfaceDeleteCommand, LOCAL_AUTH,
82040561Sbrian   "Delete iface address", "iface delete addr", (void *)1},
82140561Sbrian  {"show", NULL, iface_Show, LOCAL_AUTH,
82240561Sbrian   "Show iface address(es)", "iface show"},
82340561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
82450059Sbrian   "Display this message", "nat help|? [command]", IfaceCommands},
82540561Sbrian  {NULL, NULL, NULL},
82640561Sbrian};
82740561Sbrian
82830715Sbrianstatic struct cmdtab const Commands[] = {
82936285Sbrian  {"accept", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
83028679Sbrian  "accept option request", "accept option .."},
83128679Sbrian  {"add", NULL, AddCommand, LOCAL_AUTH,
83232109Sbrian  "add route", "add dest mask gateway", NULL},
83336285Sbrian  {NULL, "add!", AddCommand, LOCAL_AUTH,
83432109Sbrian  "add or change route", "add! dest mask gateway", (void *)1},
83540561Sbrian  {"allow", "auth", RunListCommand, LOCAL_AUTH,
83640561Sbrian  "Allow ppp access", "allow users|modes ....", AllowCommands},
83728679Sbrian  {"bg", "!bg", BgShellCommand, LOCAL_AUTH,
83831372Sbrian  "Run a background command", "[!]bg command"},
83936934Sbrian  {"clear", NULL, ClearCommand, LOCAL_AUTH | LOCAL_CX_OPT,
84046686Sbrian  "Clear throughput statistics",
84181634Sbrian  "clear ipcp|ipv6cp|physical [current|overall|peak]..."},
84236285Sbrian  {"clone", NULL, CloneCommand, LOCAL_AUTH | LOCAL_CX,
84336285Sbrian  "Clone a link", "clone newname..."},
84436285Sbrian  {"close", NULL, CloseCommand, LOCAL_AUTH | LOCAL_CX_OPT,
84536285Sbrian  "Close an FSM", "close [lcp|ccp]"},
84628679Sbrian  {"delete", NULL, DeleteCommand, LOCAL_AUTH,
84732109Sbrian  "delete route", "delete dest", NULL},
84836285Sbrian  {NULL, "delete!", DeleteCommand, LOCAL_AUTH,
84932109Sbrian  "delete a route if it exists", "delete! dest", (void *)1},
85036285Sbrian  {"deny", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
85128679Sbrian  "Deny option request", "deny option .."},
85236285Sbrian  {"dial", "call", DialCommand, LOCAL_AUTH | LOCAL_CX_OPT,
85340797Sbrian  "Dial and login", "dial|call [system ...]", NULL},
85436285Sbrian  {"disable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
85528679Sbrian  "Disable option", "disable option .."},
85636285Sbrian  {"down", NULL, DownCommand, LOCAL_AUTH | LOCAL_CX_OPT,
85746686Sbrian  "Generate a down event", "down [ccp|lcp]"},
85836285Sbrian  {"enable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
85928679Sbrian  "Enable option", "enable option .."},
86063484Sbrian  {"ident", NULL, IdentCommand, LOCAL_AUTH | LOCAL_CX,
86163484Sbrian  "Set the link identity", "ident text..."},
86240561Sbrian  {"iface", "interface", RunListCommand, LOCAL_AUTH,
86340561Sbrian  "interface control", "iface option ...", IfaceCommands},
86436285Sbrian  {"link", "datalink", LinkCommand, LOCAL_AUTH,
86536285Sbrian  "Link specific commands", "link name command ..."},
86637008Sbrian  {"load", NULL, LoadCommand, LOCAL_AUTH | LOCAL_CX_OPT,
86740797Sbrian  "Load settings", "load [system ...]"},
86885991Sbrian  {"log", NULL, LogCommand, LOCAL_AUTH | LOCAL_CX_OPT,
86985991Sbrian  "log information", "log word ..."},
87050059Sbrian#ifndef NONAT
87150059Sbrian  {"nat", "alias", RunListCommand, LOCAL_AUTH,
87258867Sbrian  "NAT control", "nat option yes|no", NatCommands},
87350059Sbrian#endif
87436285Sbrian  {"open", NULL, OpenCommand, LOCAL_AUTH | LOCAL_CX_OPT,
87537955Sbrian  "Open an FSM", "open! [lcp|ccp|ipcp]", (void *)1},
87636285Sbrian  {"passwd", NULL, PasswdCommand, LOCAL_NO_AUTH,
87736285Sbrian  "Password for manipulation", "passwd LocalPassword"},
87836285Sbrian  {"quit", "bye", QuitCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
87936285Sbrian  "Quit PPP program", "quit|bye [all]"},
88036285Sbrian  {"remove", "rm", RemoveCommand, LOCAL_AUTH | LOCAL_CX,
88136285Sbrian  "Remove a link", "remove"},
88236285Sbrian  {"rename", "mv", RenameCommand, LOCAL_AUTH | LOCAL_CX,
88336285Sbrian  "Rename a link", "rename name"},
88458044Sbrian  {"resolv", NULL, ResolvCommand, LOCAL_AUTH,
88558044Sbrian  "Manipulate resolv.conf", "resolv readonly|reload|restore|rewrite|writable"},
88628679Sbrian  {"save", NULL, SaveCommand, LOCAL_AUTH,
88728679Sbrian  "Save settings", "save"},
88863484Sbrian  {"sendident", NULL, SendIdentification, LOCAL_AUTH | LOCAL_CX,
88963484Sbrian  "Transmit the link identity", "sendident"},
89036285Sbrian  {"set", "setup", SetCommand, LOCAL_AUTH | LOCAL_CX_OPT,
89128679Sbrian  "Set parameters", "set[up] var value"},
89228679Sbrian  {"shell", "!", FgShellCommand, LOCAL_AUTH,
89328679Sbrian  "Run a subshell", "shell|! [sh command]"},
89436285Sbrian  {"show", NULL, ShowCommand, LOCAL_AUTH | LOCAL_CX_OPT,
89531372Sbrian  "Show status and stats", "show var"},
89636285Sbrian  {"term", NULL, TerminalCommand, LOCAL_AUTH | LOCAL_CX,
89731372Sbrian  "Enter terminal mode", "term"},
89828679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
89931343Sbrian  "Display this message", "help|? [command]", Commands},
90028679Sbrian  {NULL, NULL, NULL},
9016059Samurai};
9026059Samurai
90328536Sbrianstatic int
90431343SbrianShowEscape(struct cmdargs const *arg)
9056059Samurai{
90636285Sbrian  if (arg->cx->physical->async.cfg.EscMap[32]) {
90736285Sbrian    int code, bit;
90836285Sbrian    const char *sep = "";
9096059Samurai
91026516Sbrian    for (code = 0; code < 32; code++)
91136285Sbrian      if (arg->cx->physical->async.cfg.EscMap[code])
91228679Sbrian	for (bit = 0; bit < 8; bit++)
91336285Sbrian	  if (arg->cx->physical->async.cfg.EscMap[code] & (1 << bit)) {
91436285Sbrian	    prompt_Printf(arg->prompt, "%s0x%02x", sep, (code << 3) + bit);
91536285Sbrian            sep = ", ";
91636285Sbrian          }
91736285Sbrian    prompt_Printf(arg->prompt, "\n");
9186059Samurai  }
91931077Sbrian  return 0;
9206059Samurai}
9216059Samurai
92228679Sbrianstatic int
92336285SbrianShowTimerList(struct cmdargs const *arg)
9246059Samurai{
92536285Sbrian  timer_Show(0, arg->prompt);
92631077Sbrian  return 0;
9276059Samurai}
9286059Samurai
92928679Sbrianstatic int
93031343SbrianShowStopped(struct cmdargs const *arg)
93128327Sbrian{
93236285Sbrian  prompt_Printf(arg->prompt, " Stopped Timer:  LCP: ");
93336285Sbrian  if (!arg->cx->physical->link.lcp.fsm.StoppedTimer.load)
93436285Sbrian    prompt_Printf(arg->prompt, "Disabled");
93528327Sbrian  else
93636285Sbrian    prompt_Printf(arg->prompt, "%ld secs",
93736285Sbrian                  arg->cx->physical->link.lcp.fsm.StoppedTimer.load / SECTICKS);
93828461Sbrian
93936285Sbrian  prompt_Printf(arg->prompt, ", CCP: ");
94036285Sbrian  if (!arg->cx->physical->link.ccp.fsm.StoppedTimer.load)
94136285Sbrian    prompt_Printf(arg->prompt, "Disabled");
94228461Sbrian  else
94336285Sbrian    prompt_Printf(arg->prompt, "%ld secs",
94436285Sbrian                  arg->cx->physical->link.ccp.fsm.StoppedTimer.load / SECTICKS);
94528461Sbrian
94636285Sbrian  prompt_Printf(arg->prompt, "\n");
94728461Sbrian
94831077Sbrian  return 0;
94928327Sbrian}
95028327Sbrian
95128679Sbrianstatic int
95231343SbrianShowVersion(struct cmdargs const *arg)
9536059Samurai{
95451026Sbrian  prompt_Printf(arg->prompt, "PPP Version %s - %s\n", Version, __DATE__);
95531077Sbrian  return 0;
9566059Samurai}
9576059Samurai
95828679Sbrianstatic int
95936285SbrianShowProtocolStats(struct cmdargs const *arg)
96026326Sbrian{
96136285Sbrian  struct link *l = command_ChooseLink(arg);
96226326Sbrian
96336285Sbrian  prompt_Printf(arg->prompt, "%s:\n", l->name);
96436285Sbrian  link_ReportProtocolStatus(l, arg->prompt);
96531077Sbrian  return 0;
96626326Sbrian}
96726326Sbrian
96830715Sbrianstatic struct cmdtab const ShowCommands[] = {
96936285Sbrian  {"bundle", NULL, bundle_ShowStatus, LOCAL_AUTH,
97036285Sbrian  "bundle details", "show bundle"},
97136285Sbrian  {"ccp", NULL, ccp_ReportStatus, LOCAL_AUTH | LOCAL_CX_OPT,
97236285Sbrian  "CCP status", "show cpp"},
97336285Sbrian  {"compress", NULL, sl_Show, LOCAL_AUTH,
97436285Sbrian  "VJ compression stats", "show compress"},
97536285Sbrian  {"escape", NULL, ShowEscape, LOCAL_AUTH | LOCAL_CX,
97636285Sbrian  "escape characters", "show escape"},
97736285Sbrian  {"filter", NULL, filter_Show, LOCAL_AUTH,
97836285Sbrian  "packet filters", "show filter [in|out|dial|alive]"},
97936285Sbrian  {"hdlc", NULL, hdlc_ReportStatus, LOCAL_AUTH | LOCAL_CX,
98036285Sbrian  "HDLC errors", "show hdlc"},
98140561Sbrian  {"iface", "interface", iface_Show, LOCAL_AUTH,
98240561Sbrian  "Interface status", "show iface"},
98336285Sbrian  {"ipcp", NULL, ipcp_Show, LOCAL_AUTH,
98436285Sbrian  "IPCP status", "show ipcp"},
98581634Sbrian#ifndef NOINET6
98681634Sbrian  {"ipv6cp", NULL, ipv6cp_Show, LOCAL_AUTH,
98781634Sbrian  "IPV6CP status", "show ipv6cp"},
98881634Sbrian#endif
98947211Sbrian  {"layers", NULL, link_ShowLayers, LOCAL_AUTH | LOCAL_CX_OPT,
99047211Sbrian  "Protocol layers", "show layers"},
99136285Sbrian  {"lcp", NULL, lcp_ReportStatus, LOCAL_AUTH | LOCAL_CX,
99236285Sbrian  "LCP status", "show lcp"},
99336285Sbrian  {"link", "datalink", datalink_Show, LOCAL_AUTH | LOCAL_CX,
99436285Sbrian  "(high-level) link info", "show link"},
99536285Sbrian  {"links", NULL, bundle_ShowLinks, LOCAL_AUTH,
99636285Sbrian  "available link names", "show links"},
99736285Sbrian  {"log", NULL, log_ShowLevel, LOCAL_AUTH,
99836285Sbrian  "log levels", "show log"},
99936285Sbrian  {"mem", NULL, mbuf_Show, LOCAL_AUTH,
100036285Sbrian  "mbuf allocations", "show mem"},
100181634Sbrian  {"ncp", NULL, ncp_Show, LOCAL_AUTH,
100281634Sbrian  "NCP status", "show ncp"},
100346686Sbrian  {"physical", NULL, physical_ShowStatus, LOCAL_AUTH | LOCAL_CX,
100446686Sbrian  "(low-level) link info", "show physical"},
100536285Sbrian  {"mp", "multilink", mp_ShowStatus, LOCAL_AUTH,
100636285Sbrian  "multilink setup", "show mp"},
100736285Sbrian  {"proto", NULL, ShowProtocolStats, LOCAL_AUTH | LOCAL_CX_OPT,
100836285Sbrian  "protocol summary", "show proto"},
100936285Sbrian  {"route", NULL, route_Show, LOCAL_AUTH,
101036285Sbrian  "routing table", "show route"},
101136285Sbrian  {"stopped", NULL, ShowStopped, LOCAL_AUTH | LOCAL_CX,
101236285Sbrian  "STOPPED timeout", "show stopped"},
101336285Sbrian  {"timers", NULL, ShowTimerList, LOCAL_AUTH,
101436285Sbrian  "alarm timers", "show timers"},
101528679Sbrian  {"version", NULL, ShowVersion, LOCAL_NO_AUTH | LOCAL_AUTH,
101636285Sbrian  "version string", "show version"},
101736285Sbrian  {"who", NULL, log_ShowWho, LOCAL_AUTH,
101836285Sbrian  "client list", "show who"},
101928679Sbrian  {"help", "?", HelpCommand, LOCAL_NO_AUTH | LOCAL_AUTH,
102031343Sbrian  "Display this message", "show help|? [command]", ShowCommands},
102128679Sbrian  {NULL, NULL, NULL},
10226059Samurai};
10236059Samurai
102430715Sbrianstatic struct cmdtab const *
102531343SbrianFindCommand(struct cmdtab const *cmds, const char *str, int *pmatch)
10266059Samurai{
102726516Sbrian  int nmatch;
102826516Sbrian  int len;
102928679Sbrian  struct cmdtab const *found;
10306059Samurai
103126516Sbrian  found = NULL;
103226516Sbrian  len = strlen(str);
103326516Sbrian  nmatch = 0;
10346059Samurai  while (cmds->func) {
103525566Sbrian    if (cmds->name && strncasecmp(str, cmds->name, len) == 0) {
103626516Sbrian      if (cmds->name[len] == '\0') {
103728679Sbrian	*pmatch = 1;
103828679Sbrian	return cmds;
103926516Sbrian      }
10406059Samurai      nmatch++;
10416059Samurai      found = cmds;
104228679Sbrian    } else if (cmds->alias && strncasecmp(str, cmds->alias, len) == 0) {
104326516Sbrian      if (cmds->alias[len] == '\0') {
104428679Sbrian	*pmatch = 1;
104528679Sbrian	return cmds;
104626516Sbrian      }
10476059Samurai      nmatch++;
10486059Samurai      found = cmds;
10496059Samurai    }
10506059Samurai    cmds++;
10516059Samurai  }
10526059Samurai  *pmatch = nmatch;
105326516Sbrian  return found;
10546059Samurai}
10556059Samurai
105636285Sbrianstatic const char *
105736285SbrianmkPrefix(int argc, char const *const *argv, char *tgt, int sz)
105836285Sbrian{
105936285Sbrian  int f, tlen, len;
106036285Sbrian
106136285Sbrian  tlen = 0;
106236285Sbrian  for (f = 0; f < argc && tlen < sz - 2; f++) {
106336285Sbrian    if (f)
106436285Sbrian      tgt[tlen++] = ' ';
106536285Sbrian    len = strlen(argv[f]);
106636285Sbrian    if (len > sz - tlen - 1)
106736285Sbrian      len = sz - tlen - 1;
106836285Sbrian    strncpy(tgt+tlen, argv[f], len);
106936285Sbrian    tlen += len;
107036285Sbrian  }
107136285Sbrian  tgt[tlen] = '\0';
107236285Sbrian  return tgt;
107336285Sbrian}
107436285Sbrian
107530715Sbrianstatic int
107636285SbrianFindExec(struct bundle *bundle, struct cmdtab const *cmds, int argc, int argn,
107736285Sbrian         char const *const *argv, struct prompt *prompt, struct datalink *cx)
10786059Samurai{
107928679Sbrian  struct cmdtab const *cmd;
10806059Samurai  int val = 1;
10816059Samurai  int nmatch;
108231343Sbrian  struct cmdargs arg;
108336285Sbrian  char prefix[100];
10846059Samurai
108536285Sbrian  cmd = FindCommand(cmds, argv[argn], &nmatch);
10866059Samurai  if (nmatch > 1)
108736285Sbrian    log_Printf(LogWARN, "%s: Ambiguous command\n",
108836285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix));
108936285Sbrian  else if (cmd && (!prompt || (cmd->lauth & prompt->auth))) {
109036285Sbrian    if ((cmd->lauth & LOCAL_CX) && !cx)
109136285Sbrian      /* We've got no context, but we require it */
109236285Sbrian      cx = bundle2datalink(bundle, NULL);
109336285Sbrian
109436285Sbrian    if ((cmd->lauth & LOCAL_CX) && !cx)
109536285Sbrian      log_Printf(LogWARN, "%s: No context (use the `link' command)\n",
109636285Sbrian                mkPrefix(argn+1, argv, prefix, sizeof prefix));
109736285Sbrian    else {
109836285Sbrian      if (cx && !(cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
109936285Sbrian        log_Printf(LogWARN, "%s: Redundant context (%s) ignored\n",
110036285Sbrian                  mkPrefix(argn+1, argv, prefix, sizeof prefix), cx->name);
110136285Sbrian        cx = NULL;
110236285Sbrian      }
110336285Sbrian      arg.cmdtab = cmds;
110436285Sbrian      arg.cmd = cmd;
110536285Sbrian      arg.argc = argc;
110636285Sbrian      arg.argn = argn+1;
110736285Sbrian      arg.argv = argv;
110836285Sbrian      arg.bundle = bundle;
110936285Sbrian      arg.cx = cx;
111036285Sbrian      arg.prompt = prompt;
111136285Sbrian      val = (*cmd->func) (&arg);
111236285Sbrian    }
111331343Sbrian  } else
111436285Sbrian    log_Printf(LogWARN, "%s: Invalid command\n",
111536285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix));
111626516Sbrian
111726516Sbrian  if (val == -1)
111895258Sdes    log_Printf(LogWARN, "usage: %s\n", cmd->syntax);
111928679Sbrian  else if (val)
112036285Sbrian    log_Printf(LogWARN, "%s: Failed %d\n",
112136285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix), val);
112226516Sbrian
112326516Sbrian  return val;
11246059Samurai}
11256059Samurai
112637009Sbrianint
112758045Sbriancommand_Expand_Interpret(char *buff, int nb, char *argv[MAXARGS], int offset)
112858045Sbrian{
112958045Sbrian  char buff2[LINE_LEN-offset];
113058045Sbrian
113158045Sbrian  InterpretArg(buff, buff2);
113258045Sbrian  strncpy(buff, buff2, LINE_LEN - offset - 1);
113358045Sbrian  buff[LINE_LEN - offset - 1] = '\0';
113458045Sbrian
113558045Sbrian  return command_Interpret(buff, nb, argv);
113658045Sbrian}
113758045Sbrian
113858045Sbrianint
113937009Sbriancommand_Interpret(char *buff, int nb, char *argv[MAXARGS])
11406059Samurai{
11416059Samurai  char *cp;
11426059Samurai
11436059Samurai  if (nb > 0) {
11446059Samurai    cp = buff + strcspn(buff, "\r\n");
11456059Samurai    if (cp)
11466059Samurai      *cp = '\0';
114755145Sbrian    return MakeArgs(buff, argv, MAXARGS, PARSE_REDUCE);
114837009Sbrian  }
114937009Sbrian  return 0;
115031121Sbrian}
11516059Samurai
115231822Sbrianstatic int
115331822Sbrianarghidden(int argc, char const *const *argv, int n)
115431822Sbrian{
115531822Sbrian  /* Is arg n of the given command to be hidden from the log ? */
115631828Sbrian
115731828Sbrian  /* set authkey xxxxx */
115831828Sbrian  /* set key xxxxx */
115931822Sbrian  if (n == 2 && !strncasecmp(argv[0], "se", 2) &&
116031822Sbrian      (!strncasecmp(argv[1], "authk", 5) || !strncasecmp(argv[1], "ke", 2)))
116131822Sbrian    return 1;
116231822Sbrian
116331828Sbrian  /* passwd xxxxx */
116431828Sbrian  if (n == 1 && !strncasecmp(argv[0], "p", 1))
116531828Sbrian    return 1;
116631828Sbrian
116736285Sbrian  /* set server port xxxxx .... */
116836285Sbrian  if (n == 3 && !strncasecmp(argv[0], "se", 2) &&
116936285Sbrian      !strncasecmp(argv[1], "se", 2))
117036285Sbrian    return 1;
117136285Sbrian
117231822Sbrian  return 0;
117331822Sbrian}
117431822Sbrian
117531121Sbrianvoid
117636285Sbriancommand_Run(struct bundle *bundle, int argc, char const *const *argv,
117737008Sbrian           struct prompt *prompt, const char *label, struct datalink *cx)
117831121Sbrian{
117931156Sbrian  if (argc > 0) {
118036285Sbrian    if (log_IsKept(LogCOMMAND)) {
118147844Sbrian      char buf[LINE_LEN];
118231156Sbrian      int f, n;
118331156Sbrian
118431156Sbrian      if (label) {
118531962Sbrian        strncpy(buf, label, sizeof buf - 3);
118631962Sbrian        buf[sizeof buf - 3] = '\0';
118731156Sbrian        strcat(buf, ": ");
118847844Sbrian        n = strlen(buf);
118947844Sbrian      } else {
119047844Sbrian        *buf = '\0';
119147844Sbrian        n = 0;
119231156Sbrian      }
119347844Sbrian      buf[sizeof buf - 1] = '\0';	/* In case we run out of room in buf */
119447844Sbrian
119531156Sbrian      for (f = 0; f < argc; f++) {
119631962Sbrian        if (n < sizeof buf - 1 && f)
119731156Sbrian          buf[n++] = ' ';
119831822Sbrian        if (arghidden(argc, argv, f))
119936285Sbrian          strncpy(buf+n, "********", sizeof buf - n - 1);
120031822Sbrian        else
120131962Sbrian          strncpy(buf+n, argv[f], sizeof buf - n - 1);
120231156Sbrian        n += strlen(buf+n);
120331156Sbrian      }
120436285Sbrian      log_Printf(LogCOMMAND, "%s\n", buf);
120531156Sbrian    }
120637008Sbrian    FindExec(bundle, Commands, argc, 0, argv, prompt, cx);
120731156Sbrian  }
12086059Samurai}
12096059Samurai
121054914Sbrianint
121136285Sbriancommand_Decode(struct bundle *bundle, char *buff, int nb, struct prompt *prompt,
121236285Sbrian              const char *label)
121331121Sbrian{
121431121Sbrian  int argc;
121537009Sbrian  char *argv[MAXARGS];
121631121Sbrian
121758045Sbrian  if ((argc = command_Expand_Interpret(buff, nb, argv, 0)) < 0)
121854914Sbrian    return 0;
121954914Sbrian
122037008Sbrian  command_Run(bundle, argc, (char const *const *)argv, prompt, label, NULL);
122154914Sbrian  return 1;
122231121Sbrian}
122331121Sbrian
12246059Samuraistatic int
122531343SbrianShowCommand(struct cmdargs const *arg)
12266059Samurai{
122736285Sbrian  if (!arg->prompt)
122836285Sbrian    log_Printf(LogWARN, "show: Cannot show without a prompt\n");
122936285Sbrian  else if (arg->argc > arg->argn)
123036285Sbrian    FindExec(arg->bundle, ShowCommands, arg->argc, arg->argn, arg->argv,
123136285Sbrian             arg->prompt, arg->cx);
12326059Samurai  else
123336285Sbrian    prompt_Printf(arg->prompt, "Use ``show ?'' to get a list.\n");
123426516Sbrian
123526516Sbrian  return 0;
12366059Samurai}
12376059Samurai
12386059Samuraistatic int
123931343SbrianTerminalCommand(struct cmdargs const *arg)
12406059Samurai{
124136285Sbrian  if (!arg->prompt) {
124236285Sbrian    log_Printf(LogWARN, "term: Need a prompt\n");
124326516Sbrian    return 1;
12446059Samurai  }
124536285Sbrian
124636285Sbrian  if (arg->cx->physical->link.lcp.fsm.state > ST_CLOSED) {
124736285Sbrian    prompt_Printf(arg->prompt, "LCP state is [%s]\n",
124836285Sbrian                  State2Nam(arg->cx->physical->link.lcp.fsm.state));
124936285Sbrian    return 1;
12506059Samurai  }
125136285Sbrian
125236285Sbrian  datalink_Up(arg->cx, 0, 0);
125336285Sbrian  prompt_TtyTermMode(arg->prompt, arg->cx);
125436285Sbrian  return 0;
12556059Samurai}
12566059Samurai
12576059Samuraistatic int
125831343SbrianQuitCommand(struct cmdargs const *arg)
12596059Samurai{
126036285Sbrian  if (!arg->prompt || prompt_IsController(arg->prompt) ||
126136285Sbrian      (arg->argc > arg->argn && !strcasecmp(arg->argv[arg->argn], "all") &&
126236285Sbrian       (arg->prompt->auth & LOCAL_AUTH)))
126336285Sbrian    Cleanup(EX_NORMAL);
126436285Sbrian  if (arg->prompt)
126536285Sbrian    prompt_Destroy(arg->prompt, 1);
126626516Sbrian
126726516Sbrian  return 0;
12686059Samurai}
12696059Samurai
12706059Samuraistatic int
127136285SbrianOpenCommand(struct cmdargs const *arg)
12726059Samurai{
127337160Sbrian  if (arg->argc == arg->argn)
127437993Sbrian    bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1);
127537160Sbrian  else if (arg->argc == arg->argn + 1) {
127637160Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp")) {
127737385Sbrian      struct datalink *cx = arg->cx ?
127837385Sbrian        arg->cx : bundle2datalink(arg->bundle, NULL);
127937385Sbrian      if (cx) {
128037385Sbrian        if (cx->physical->link.lcp.fsm.state == ST_OPENED)
128137385Sbrian          fsm_Reopen(&cx->physical->link.lcp.fsm);
128237160Sbrian        else
128337993Sbrian          bundle_Open(arg->bundle, cx->name, PHYS_ALL, 1);
128437160Sbrian      } else
128537160Sbrian        log_Printf(LogWARN, "open lcp: You must specify a link\n");
128637160Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) {
128737160Sbrian      struct fsm *fp;
12886059Samurai
128937210Sbrian      fp = &command_ChooseLink(arg)->ccp.fsm;
129037160Sbrian      if (fp->link->lcp.fsm.state != ST_OPENED)
129137160Sbrian        log_Printf(LogWARN, "open: LCP must be open before opening CCP\n");
129237160Sbrian      else if (fp->state == ST_OPENED)
129337160Sbrian        fsm_Reopen(fp);
129437160Sbrian      else {
129537160Sbrian        fp->open_mode = 0;	/* Not passive any more */
129637160Sbrian        if (fp->state == ST_STOPPED) {
129737160Sbrian          fsm_Down(fp);
129837160Sbrian          fsm_Up(fp);
129937160Sbrian        } else {
130037160Sbrian          fsm_Up(fp);
130137160Sbrian          fsm_Open(fp);
130237160Sbrian        }
130336285Sbrian      }
130437160Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ipcp")) {
130537160Sbrian      if (arg->cx)
130637160Sbrian        log_Printf(LogWARN, "open ipcp: You need not specify a link\n");
130737160Sbrian      if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED)
130837160Sbrian        fsm_Reopen(&arg->bundle->ncp.ipcp.fsm);
130937160Sbrian      else
131037993Sbrian        bundle_Open(arg->bundle, NULL, PHYS_ALL, 1);
131137160Sbrian    } else
131237160Sbrian      return -1;
131336285Sbrian  } else
131436285Sbrian    return -1;
131536285Sbrian
131626516Sbrian  return 0;
13176059Samurai}
13186059Samurai
131925067Sbrianstatic int
132036285SbrianCloseCommand(struct cmdargs const *arg)
13216059Samurai{
132237007Sbrian  if (arg->argc == arg->argn)
132337007Sbrian    bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_STAYDOWN);
132437007Sbrian  else if (arg->argc == arg->argn + 1) {
132537007Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp"))
132637007Sbrian      bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_LCP);
132737007Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "ccp") ||
132837007Sbrian             !strcasecmp(arg->argv[arg->argn], "ccp!")) {
132937007Sbrian      struct fsm *fp;
13306059Samurai
133137210Sbrian      fp = &command_ChooseLink(arg)->ccp.fsm;
133237007Sbrian      if (fp->state == ST_OPENED) {
133337007Sbrian        fsm_Close(fp);
133437007Sbrian        if (arg->argv[arg->argn][3] == '!')
133537007Sbrian          fp->open_mode = 0;		/* Stay ST_CLOSED */
133637007Sbrian        else
133737007Sbrian          fp->open_mode = OPEN_PASSIVE;	/* Wait for the peer to start */
133837007Sbrian      }
133937007Sbrian    } else
134036285Sbrian      return -1;
134136285Sbrian  } else
134236285Sbrian    return -1;
134336285Sbrian
134436285Sbrian  return 0;
13456059Samurai}
13466059Samurai
134725067Sbrianstatic int
134836285SbrianDownCommand(struct cmdargs const *arg)
134911336Samurai{
135037018Sbrian  if (arg->argc == arg->argn) {
135137018Sbrian      if (arg->cx)
135237018Sbrian        datalink_Down(arg->cx, CLOSE_STAYDOWN);
135337018Sbrian      else
135437018Sbrian        bundle_Down(arg->bundle, CLOSE_STAYDOWN);
135537018Sbrian  } else if (arg->argc == arg->argn + 1) {
135637018Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp")) {
135737018Sbrian      if (arg->cx)
135837018Sbrian        datalink_Down(arg->cx, CLOSE_LCP);
135937018Sbrian      else
136037018Sbrian        bundle_Down(arg->bundle, CLOSE_LCP);
136137018Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) {
136237018Sbrian      struct fsm *fp = arg->cx ? &arg->cx->physical->link.ccp.fsm :
136337018Sbrian                                 &arg->bundle->ncp.mp.link.ccp.fsm;
136437060Sbrian      fsm2initial(fp);
136537018Sbrian    } else
136637018Sbrian      return -1;
136736285Sbrian  } else
136836285Sbrian    return -1;
136936285Sbrian
137036285Sbrian  return 0;
137125067Sbrian}
137225067Sbrian
137325067Sbrianstatic int
137436285SbrianSetModemSpeed(struct cmdargs const *arg)
137525067Sbrian{
137636285Sbrian  long speed;
137736285Sbrian  char *end;
137811336Samurai
137936285Sbrian  if (arg->argc > arg->argn && *arg->argv[arg->argn]) {
138036285Sbrian    if (arg->argc > arg->argn+1) {
138154917Sbrian      log_Printf(LogWARN, "SetModemSpeed: Too many arguments\n");
138236285Sbrian      return -1;
138311336Samurai    }
138436285Sbrian    if (strcasecmp(arg->argv[arg->argn], "sync") == 0) {
138536285Sbrian      physical_SetSync(arg->cx->physical);
138636285Sbrian      return 0;
138736285Sbrian    }
138836285Sbrian    end = NULL;
138936285Sbrian    speed = strtol(arg->argv[arg->argn], &end, 10);
139036285Sbrian    if (*end) {
139136285Sbrian      log_Printf(LogWARN, "SetModemSpeed: Bad argument \"%s\"",
139236285Sbrian                arg->argv[arg->argn]);
139336285Sbrian      return -1;
139436285Sbrian    }
139536285Sbrian    if (physical_SetSpeed(arg->cx->physical, speed))
139636285Sbrian      return 0;
139736285Sbrian    log_Printf(LogWARN, "%s: Invalid speed\n", arg->argv[arg->argn]);
139836285Sbrian  } else
139936285Sbrian    log_Printf(LogWARN, "SetModemSpeed: No speed specified\n");
140024939Sbrian
140126516Sbrian  return -1;
140211336Samurai}
140311336Samurai
140425067Sbrianstatic int
140531343SbrianSetStoppedTimeout(struct cmdargs const *arg)
140628327Sbrian{
140736285Sbrian  struct link *l = &arg->cx->physical->link;
140836285Sbrian
140936285Sbrian  l->lcp.fsm.StoppedTimer.load = 0;
141036285Sbrian  l->ccp.fsm.StoppedTimer.load = 0;
141136285Sbrian  if (arg->argc <= arg->argn+2) {
141236285Sbrian    if (arg->argc > arg->argn) {
141336285Sbrian      l->lcp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn]) * SECTICKS;
141436285Sbrian      if (arg->argc > arg->argn+1)
141536285Sbrian        l->ccp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn+1]) * SECTICKS;
141628461Sbrian    }
141728327Sbrian    return 0;
141828327Sbrian  }
141928327Sbrian  return -1;
142028327Sbrian}
142128327Sbrian
142228327Sbrianstatic int
142331343SbrianSetServer(struct cmdargs const *arg)
142426940Sbrian{
142526940Sbrian  int res = -1;
142626940Sbrian
142736285Sbrian  if (arg->argc > arg->argn && arg->argc < arg->argn+4) {
142831081Sbrian    const char *port, *passwd, *mask;
142953125Sbrian    int mlen;
143031081Sbrian
143131081Sbrian    /* What's what ? */
143236285Sbrian    port = arg->argv[arg->argn];
143336285Sbrian    if (arg->argc == arg->argn + 2) {
143436285Sbrian      passwd = arg->argv[arg->argn+1];
143536285Sbrian      mask = NULL;
143636285Sbrian    } else if (arg->argc == arg->argn + 3) {
143736285Sbrian      passwd = arg->argv[arg->argn+1];
143836285Sbrian      mask = arg->argv[arg->argn+2];
143953125Sbrian      mlen = strlen(mask);
144053125Sbrian      if (mlen == 0 || mlen > 4 || strspn(mask, "01234567") != mlen ||
144153125Sbrian          (mlen == 4 && *mask != '0')) {
144253125Sbrian        log_Printf(LogWARN, "%s %s: %s: Invalid mask\n",
144353125Sbrian                   arg->argv[arg->argn - 2], arg->argv[arg->argn - 1], mask);
144431081Sbrian        return -1;
144553125Sbrian      }
144671764Sbrian    } else if (arg->argc != arg->argn + 1)
144771764Sbrian      return -1;
144871764Sbrian    else if (strcasecmp(port, "none") == 0) {
144971657Sbrian      if (server_Clear(arg->bundle))
145071657Sbrian        log_Printf(LogPHASE, "Disabled server socket\n");
145171657Sbrian      return 0;
145271657Sbrian    } else if (strcasecmp(port, "open") == 0) {
145371657Sbrian      switch (server_Reopen(arg->bundle)) {
145471657Sbrian        case SERVER_OK:
145571657Sbrian          return 0;
145671657Sbrian        case SERVER_FAILED:
145771764Sbrian          log_Printf(LogWARN, "Failed to reopen server port\n");
145871657Sbrian          return 1;
145971657Sbrian        case SERVER_UNSET:
146071764Sbrian          log_Printf(LogWARN, "Cannot reopen unset server socket\n");
146171657Sbrian          return 1;
146271657Sbrian        default:
146371657Sbrian          break;
146471657Sbrian      }
146571657Sbrian      return -1;
146671657Sbrian    } else if (strcasecmp(port, "closed") == 0) {
146736285Sbrian      if (server_Close(arg->bundle))
146871657Sbrian        log_Printf(LogPHASE, "Closed server socket\n");
146971657Sbrian      else
147071657Sbrian        log_Printf(LogWARN, "Server socket not open\n");
147171657Sbrian
147236285Sbrian      return 0;
147331081Sbrian    } else
147436285Sbrian      return -1;
147531081Sbrian
147671657Sbrian    strncpy(server.cfg.passwd, passwd, sizeof server.cfg.passwd - 1);
147771657Sbrian    server.cfg.passwd[sizeof server.cfg.passwd - 1] = '\0';
147831081Sbrian
147936285Sbrian    if (*port == '/') {
148031081Sbrian      mode_t imask;
148136285Sbrian      char *ptr, name[LINE_LEN + 12];
148228679Sbrian
148353125Sbrian      if (mask == NULL)
148431081Sbrian        imask = (mode_t)-1;
148553125Sbrian      else for (imask = mlen = 0; mask[mlen]; mlen++)
148653125Sbrian        imask = (imask * 8) + mask[mlen] - '0';
148736285Sbrian
148836285Sbrian      ptr = strstr(port, "%d");
148936285Sbrian      if (ptr) {
149036285Sbrian        snprintf(name, sizeof name, "%.*s%d%s",
149137210Sbrian                 (int)(ptr - port), port, arg->bundle->unit, ptr + 2);
149236285Sbrian        port = name;
149336285Sbrian      }
149436285Sbrian      res = server_LocalOpen(arg->bundle, port, imask);
149527346Sbrian    } else {
149636285Sbrian      int iport, add = 0;
149728679Sbrian
149831081Sbrian      if (mask != NULL)
149931081Sbrian        return -1;
150028679Sbrian
150136285Sbrian      if (*port == '+') {
150236285Sbrian        port++;
150336285Sbrian        add = 1;
150436285Sbrian      }
150531081Sbrian      if (strspn(port, "0123456789") != strlen(port)) {
150631081Sbrian        struct servent *s;
150731081Sbrian
150831081Sbrian        if ((s = getservbyname(port, "tcp")) == NULL) {
150931081Sbrian	  iport = 0;
151036285Sbrian	  log_Printf(LogWARN, "%s: Invalid port or service\n", port);
151128679Sbrian	} else
151231081Sbrian	  iport = ntohs(s->s_port);
151327346Sbrian      } else
151431081Sbrian        iport = atoi(port);
151536285Sbrian
151636285Sbrian      if (iport) {
151736285Sbrian        if (add)
151836285Sbrian          iport += arg->bundle->unit;
151936285Sbrian        res = server_TcpOpen(arg->bundle, iport);
152036285Sbrian      } else
152136285Sbrian        res = -1;
152227346Sbrian    }
152331081Sbrian  }
152426940Sbrian
152526940Sbrian  return res;
152626940Sbrian}
152726940Sbrian
152826940Sbrianstatic int
152931343SbrianSetEscape(struct cmdargs const *arg)
15306059Samurai{
15316059Samurai  int code;
153236285Sbrian  int argc = arg->argc - arg->argn;
153336285Sbrian  char const *const *argv = arg->argv + arg->argn;
15346059Samurai
15356059Samurai  for (code = 0; code < 33; code++)
153636285Sbrian    arg->cx->physical->async.cfg.EscMap[code] = 0;
153731343Sbrian
15386059Samurai  while (argc-- > 0) {
15396059Samurai    sscanf(*argv++, "%x", &code);
15406059Samurai    code &= 0xff;
154136285Sbrian    arg->cx->physical->async.cfg.EscMap[code >> 3] |= (1 << (code & 7));
154236285Sbrian    arg->cx->physical->async.cfg.EscMap[32] = 1;
15436059Samurai  }
154426516Sbrian  return 0;
15456059Samurai}
15466059Samurai
15476059Samuraistatic int
154831343SbrianSetInterfaceAddr(struct cmdargs const *arg)
15496059Samurai{
155081634Sbrian  struct ncp *ncp = &arg->bundle->ncp;
155181634Sbrian  struct ncpaddr ncpaddr;
155232267Sbrian  const char *hisaddr;
155332267Sbrian
155440561Sbrian  if (arg->argc > arg->argn + 4)
155540561Sbrian    return -1;
155640561Sbrian
155732267Sbrian  hisaddr = NULL;
155881634Sbrian  memset(&ncp->ipcp.cfg.my_range, '\0', sizeof ncp->ipcp.cfg.my_range);
155981634Sbrian  memset(&ncp->ipcp.cfg.peer_range, '\0', sizeof ncp->ipcp.cfg.peer_range);
156081634Sbrian  ncp->ipcp.cfg.HaveTriggerAddress = 0;
156181634Sbrian  ncp->ipcp.cfg.netmask.s_addr = INADDR_ANY;
156281634Sbrian  iplist_reset(&ncp->ipcp.cfg.peer_list);
156328394Sbrian
156436285Sbrian  if (arg->argc > arg->argn) {
156581634Sbrian    if (!ncprange_aton(&ncp->ipcp.cfg.my_range, ncp, arg->argv[arg->argn]))
156628679Sbrian      return 1;
156736285Sbrian    if (arg->argc > arg->argn+1) {
156836285Sbrian      hisaddr = arg->argv[arg->argn+1];
156936285Sbrian      if (arg->argc > arg->argn+2) {
157081634Sbrian        ncp->ipcp.ifmask = ncp->ipcp.cfg.netmask =
157181634Sbrian          GetIpAddr(arg->argv[arg->argn+2]);
157236285Sbrian	if (arg->argc > arg->argn+3) {
157381634Sbrian	  ncp->ipcp.cfg.TriggerAddress = GetIpAddr(arg->argv[arg->argn+3]);
157481634Sbrian	  ncp->ipcp.cfg.HaveTriggerAddress = 1;
15759440Samurai	}
15766059Samurai      }
15776059Samurai    }
15786059Samurai  }
157928394Sbrian
158040561Sbrian  /* 0.0.0.0 means any address (0 bits) */
158181634Sbrian  ncpaddr_getip4(&ncpaddr, &ncp->ipcp.my_ip);
158281634Sbrian  ncprange_getaddr(&ncp->ipcp.cfg.my_range, &ncpaddr);
158381634Sbrian  if (ncp->ipcp.my_ip.s_addr == INADDR_ANY)
158481634Sbrian    ncprange_setwidth(&ncp->ipcp.cfg.my_range, 0);
158581634Sbrian  bundle_AdjustFilters(arg->bundle, &ncpaddr, NULL);
158636285Sbrian
158736285Sbrian  if (hisaddr && !ipcp_UseHisaddr(arg->bundle, hisaddr,
158836928Sbrian                                  arg->bundle->phys_type.all & PHYS_AUTO))
158932267Sbrian    return 4;
159031121Sbrian
159126516Sbrian  return 0;
15926059Samurai}
15936059Samurai
159418752Sjkhstatic int
159544305SbrianSetRetry(int argc, char const *const *argv, u_int *timeout, u_int *maxreq,
159644305Sbrian          u_int *maxtrm, int def)
159744305Sbrian{
159844305Sbrian  if (argc == 0) {
159944305Sbrian    *timeout = DEF_FSMRETRY;
160044305Sbrian    *maxreq = def;
160144305Sbrian    if (maxtrm != NULL)
160244305Sbrian      *maxtrm = def;
160344305Sbrian  } else {
160444305Sbrian    long l = atol(argv[0]);
160544305Sbrian
160644305Sbrian    if (l < MIN_FSMRETRY) {
160744305Sbrian      log_Printf(LogWARN, "%ld: Invalid FSM retry period - min %d\n",
160844305Sbrian                 l, MIN_FSMRETRY);
160944305Sbrian      return 1;
161044305Sbrian    } else
161144305Sbrian      *timeout = l;
161244305Sbrian
161344305Sbrian    if (argc > 1) {
161444305Sbrian      l = atol(argv[1]);
161544305Sbrian      if (l < 1) {
161644305Sbrian        log_Printf(LogWARN, "%ld: Invalid FSM REQ tries - changed to 1\n", l);
161744305Sbrian        l = 1;
161844305Sbrian      }
161944305Sbrian      *maxreq = l;
162044305Sbrian
162144305Sbrian      if (argc > 2 && maxtrm != NULL) {
162244305Sbrian        l = atol(argv[2]);
162344305Sbrian        if (l < 1) {
162444305Sbrian          log_Printf(LogWARN, "%ld: Invalid FSM TRM tries - changed to 1\n", l);
162544305Sbrian          l = 1;
162644305Sbrian        }
162744305Sbrian        *maxtrm = l;
162844305Sbrian      }
162944305Sbrian    }
163044305Sbrian  }
163144305Sbrian
163244305Sbrian  return 0;
163344305Sbrian}
163444305Sbrian
163544305Sbrianstatic int
163631343SbrianSetVariable(struct cmdargs const *arg)
16376059Samurai{
163837210Sbrian  long long_val, param = (long)arg->cmd->args;
163979119Sbrian  int mode, dummyint, f, first, res;
164078410Sbrian  u_short *change;
164131343Sbrian  const char *argp;
164236285Sbrian  struct datalink *cx = arg->cx;	/* LOCAL_CX uses this */
164336285Sbrian  struct link *l = command_ChooseLink(arg);	/* LOCAL_CX_OPT uses this */
164481634Sbrian  struct in_addr *ipaddr;
164581634Sbrian  struct ncpaddr ncpaddr[2];
16466059Samurai
164736285Sbrian  if (arg->argc > arg->argn)
164836285Sbrian    argp = arg->argv[arg->argn];
164926551Sbrian  else
165031343Sbrian    argp = "";
165126551Sbrian
165279119Sbrian  res = 0;
165379119Sbrian
165436285Sbrian  if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
165536285Sbrian    log_Printf(LogWARN, "set %s: No context (use the `link' command)\n",
165636285Sbrian              arg->cmd->name);
165736285Sbrian    return 1;
165836285Sbrian  } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
165936285Sbrian    log_Printf(LogWARN, "set %s: Redundant context (%s) ignored\n",
166036285Sbrian              arg->cmd->name, cx->name);
166136285Sbrian    cx = NULL;
166236285Sbrian  }
166336285Sbrian
166426551Sbrian  switch (param) {
166528679Sbrian  case VAR_AUTHKEY:
166650139Sbrian    strncpy(arg->bundle->cfg.auth.key, argp,
166750139Sbrian            sizeof arg->bundle->cfg.auth.key - 1);
166850139Sbrian    arg->bundle->cfg.auth.key[sizeof arg->bundle->cfg.auth.key - 1] = '\0';
166928679Sbrian    break;
167037210Sbrian
167128679Sbrian  case VAR_AUTHNAME:
167240622Sbrian    switch (bundle_Phase(arg->bundle)) {
167358880Sbrian      default:
167458880Sbrian        log_Printf(LogWARN, "Altering authname while at phase %s\n",
167558880Sbrian                   bundle_PhaseName(arg->bundle));
167658880Sbrian        /* drop through */
167740622Sbrian      case PHASE_DEAD:
167840622Sbrian      case PHASE_ESTABLISH:
167940622Sbrian        strncpy(arg->bundle->cfg.auth.name, argp,
168040622Sbrian                sizeof arg->bundle->cfg.auth.name - 1);
168140622Sbrian        arg->bundle->cfg.auth.name[sizeof arg->bundle->cfg.auth.name-1] = '\0';
168240622Sbrian        break;
168336285Sbrian    }
168428679Sbrian    break;
168537210Sbrian
168636285Sbrian  case VAR_AUTOLOAD:
168749434Sbrian    if (arg->argc == arg->argn + 3) {
168898243Sbrian      int v1, v2, v3;
168949434Sbrian      char *end;
169049434Sbrian
169149434Sbrian      v1 = strtol(arg->argv[arg->argn], &end, 0);
169249434Sbrian      if (v1 < 0 || *end) {
169349434Sbrian        log_Printf(LogWARN, "autoload: %s: Invalid min percentage\n",
169449434Sbrian                   arg->argv[arg->argn]);
169579119Sbrian        res = 1;
169679119Sbrian        break;
169736285Sbrian      }
169849434Sbrian
169949434Sbrian      v2 = strtol(arg->argv[arg->argn + 1], &end, 0);
170049434Sbrian      if (v2 < 0 || *end) {
170149434Sbrian        log_Printf(LogWARN, "autoload: %s: Invalid max percentage\n",
170249434Sbrian                   arg->argv[arg->argn + 1]);
170379119Sbrian        res = 1;
170479119Sbrian        break;
170549434Sbrian      }
170649434Sbrian      if (v2 < v1) {
170749434Sbrian        v3 = v1;
170849434Sbrian        v1 = v2;
170949434Sbrian        v2 = v3;
171049434Sbrian      }
171149434Sbrian
171249434Sbrian      v3 = strtol(arg->argv[arg->argn + 2], &end, 0);
171349434Sbrian      if (v3 <= 0 || *end) {
171449434Sbrian        log_Printf(LogWARN, "autoload: %s: Invalid throughput period\n",
171549434Sbrian                   arg->argv[arg->argn + 2]);
171679119Sbrian        res = 1;
171779119Sbrian        break;
171849434Sbrian      }
171949434Sbrian
172049434Sbrian      arg->bundle->ncp.mp.cfg.autoload.min = v1;
172149434Sbrian      arg->bundle->ncp.mp.cfg.autoload.max = v2;
172249434Sbrian      arg->bundle->ncp.mp.cfg.autoload.period = v3;
172349434Sbrian      mp_RestartAutoloadTimer(&arg->bundle->ncp.mp);
172436285Sbrian    } else {
172579119Sbrian      log_Printf(LogWARN, "Set autoload requires three arguments\n");
172679119Sbrian      res = 1;
172736285Sbrian    }
172836285Sbrian    break;
172937210Sbrian
173028679Sbrian  case VAR_DIAL:
173136285Sbrian    strncpy(cx->cfg.script.dial, argp, sizeof cx->cfg.script.dial - 1);
173236285Sbrian    cx->cfg.script.dial[sizeof cx->cfg.script.dial - 1] = '\0';
173328679Sbrian    break;
173437210Sbrian
173528679Sbrian  case VAR_LOGIN:
173636285Sbrian    strncpy(cx->cfg.script.login, argp, sizeof cx->cfg.script.login - 1);
173736285Sbrian    cx->cfg.script.login[sizeof cx->cfg.script.login - 1] = '\0';
173828679Sbrian    break;
173937210Sbrian
174036285Sbrian  case VAR_WINSIZE:
174136285Sbrian    if (arg->argc > arg->argn) {
174236285Sbrian      l->ccp.cfg.deflate.out.winsize = atoi(arg->argv[arg->argn]);
174336285Sbrian      if (l->ccp.cfg.deflate.out.winsize < 8 ||
174436285Sbrian          l->ccp.cfg.deflate.out.winsize > 15) {
174536285Sbrian          log_Printf(LogWARN, "%d: Invalid outgoing window size\n",
174636285Sbrian                    l->ccp.cfg.deflate.out.winsize);
174736285Sbrian          l->ccp.cfg.deflate.out.winsize = 15;
174836285Sbrian      }
174936285Sbrian      if (arg->argc > arg->argn+1) {
175036285Sbrian        l->ccp.cfg.deflate.in.winsize = atoi(arg->argv[arg->argn+1]);
175136285Sbrian        if (l->ccp.cfg.deflate.in.winsize < 8 ||
175236285Sbrian            l->ccp.cfg.deflate.in.winsize > 15) {
175336285Sbrian            log_Printf(LogWARN, "%d: Invalid incoming window size\n",
175436285Sbrian                      l->ccp.cfg.deflate.in.winsize);
175536285Sbrian            l->ccp.cfg.deflate.in.winsize = 15;
175636285Sbrian        }
175736285Sbrian      } else
175836285Sbrian        l->ccp.cfg.deflate.in.winsize = 0;
175936285Sbrian    } else {
176079119Sbrian      log_Printf(LogWARN, "No window size specified\n");
176179119Sbrian      res = 1;
176236285Sbrian    }
176336285Sbrian    break;
176437210Sbrian
176593418Sbrian#ifndef NODES
176678411Sbrian  case VAR_MPPE:
176779119Sbrian    if (arg->argc > arg->argn + 2) {
176879119Sbrian      res = -1;
176979119Sbrian      break;
177079119Sbrian    }
177178411Sbrian
177278411Sbrian    if (arg->argc == arg->argn) {
177378411Sbrian      l->ccp.cfg.mppe.keybits = 0;
177478411Sbrian      l->ccp.cfg.mppe.state = MPPE_ANYSTATE;
177578411Sbrian      l->ccp.cfg.mppe.required = 0;
177678411Sbrian      break;
177778411Sbrian    }
177878411Sbrian
177978411Sbrian    if (!strcmp(argp, "*"))
178078411Sbrian      long_val = 0;
178178411Sbrian    else {
178278411Sbrian      long_val = atol(argp);
178378411Sbrian      if (long_val != 40 && long_val != 56 && long_val != 128) {
178478411Sbrian        log_Printf(LogWARN, "%s: Invalid bits value\n", argp);
178579119Sbrian        res = -1;
178679119Sbrian        break;
178767910Sbrian      }
178867910Sbrian    }
178978411Sbrian
179078411Sbrian    if (arg->argc == arg->argn + 2) {
179178411Sbrian      if (!strcmp(arg->argv[arg->argn + 1], "*"))
179278411Sbrian        l->ccp.cfg.mppe.state = MPPE_ANYSTATE;
179378411Sbrian      else if (!strcasecmp(arg->argv[arg->argn + 1], "stateless"))
179478411Sbrian        l->ccp.cfg.mppe.state = MPPE_STATELESS;
179579370Sbrian      else if (!strcasecmp(arg->argv[arg->argn + 1], "stateful"))
179678411Sbrian        l->ccp.cfg.mppe.state = MPPE_STATEFUL;
179778411Sbrian      else {
179878411Sbrian        log_Printf(LogWARN, "%s: Invalid state value\n",
179978411Sbrian                   arg->argv[arg->argn + 1]);
180079119Sbrian        res = -1;
180179119Sbrian        break;
180278411Sbrian      }
180378411Sbrian    } else
180478411Sbrian      l->ccp.cfg.mppe.state = MPPE_ANYSTATE;
180578411Sbrian    l->ccp.cfg.mppe.keybits = long_val;
180678411Sbrian    l->ccp.cfg.mppe.required = 1;
180767910Sbrian    break;
180867910Sbrian#endif
180967910Sbrian
181028679Sbrian  case VAR_DEVICE:
181136285Sbrian    physical_SetDeviceList(cx->physical, arg->argc - arg->argn,
181236285Sbrian                           arg->argv + arg->argn);
181336285Sbrian    break;
181437210Sbrian
181536285Sbrian  case VAR_ACCMAP:
181636285Sbrian    if (arg->argc > arg->argn) {
181737210Sbrian      u_long ulong_val;
181836285Sbrian      sscanf(argp, "%lx", &ulong_val);
181937210Sbrian      cx->physical->link.lcp.cfg.accmap = (u_int32_t)ulong_val;
182036285Sbrian    } else {
182179119Sbrian      log_Printf(LogWARN, "No accmap specified\n");
182279119Sbrian      res = 1;
182336285Sbrian    }
182436285Sbrian    break;
182537210Sbrian
182636285Sbrian  case VAR_MODE:
182736285Sbrian    mode = Nam2mode(argp);
182836285Sbrian    if (mode == PHYS_NONE || mode == PHYS_ALL) {
182936285Sbrian      log_Printf(LogWARN, "%s: Invalid mode\n", argp);
183079119Sbrian      res = -1;
183179119Sbrian      break;
183236285Sbrian    }
183336285Sbrian    bundle_SetMode(arg->bundle, cx, mode);
183436285Sbrian    break;
183537210Sbrian
183636285Sbrian  case VAR_MRRU:
183740622Sbrian    switch (bundle_Phase(arg->bundle)) {
183840622Sbrian      case PHASE_DEAD:
183940622Sbrian        break;
184040622Sbrian      case PHASE_ESTABLISH:
184140622Sbrian        /* Make sure none of our links are DATALINK_LCP or greater */
184240622Sbrian        if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) {
184340622Sbrian          log_Printf(LogWARN, "mrru: Only changable before LCP negotiations\n");
184479119Sbrian          res = 1;
184579119Sbrian          break;
184640622Sbrian        }
184740622Sbrian        break;
184840622Sbrian      default:
184940622Sbrian        log_Printf(LogWARN, "mrru: Only changable at phase DEAD/ESTABLISH\n");
185079119Sbrian        res = 1;
185179119Sbrian        break;
185229696Sbrian    }
185379119Sbrian    if (res != 0)
185479119Sbrian      break;
185537210Sbrian    long_val = atol(argp);
185637210Sbrian    if (long_val && long_val < MIN_MRU) {
185737210Sbrian      log_Printf(LogWARN, "MRRU %ld: too small - min %d\n", long_val, MIN_MRU);
185879119Sbrian      res = 1;
185979119Sbrian      break;
186037210Sbrian    } else if (long_val > MAX_MRU) {
186137210Sbrian      log_Printf(LogWARN, "MRRU %ld: too big - max %d\n", long_val, MAX_MRU);
186279119Sbrian      res = 1;
186379119Sbrian      break;
186437210Sbrian    } else
186537210Sbrian      arg->bundle->ncp.mp.cfg.mrru = long_val;
186628679Sbrian    break;
186737210Sbrian
186836285Sbrian  case VAR_MRU:
186979163Sbrian    long_val = 0;	/* silence gcc */
187079163Sbrian    change = NULL;	/* silence gcc */
187178410Sbrian    switch(arg->argc - arg->argn) {
187278410Sbrian    case 1:
187379119Sbrian      if (argp[strspn(argp, "0123456789")] != '\0') {
187479119Sbrian        res = -1;
187579119Sbrian        break;
187679119Sbrian      }
187779119Sbrian      /*FALLTHRU*/
187878410Sbrian    case 0:
187978410Sbrian      long_val = atol(argp);
188078410Sbrian      change = &l->lcp.cfg.mru;
188178410Sbrian      if (long_val > l->lcp.cfg.max_mru) {
188278410Sbrian        log_Printf(LogWARN, "MRU %ld: too large - max set to %d\n", long_val,
188378410Sbrian                   l->lcp.cfg.max_mru);
188479119Sbrian        res = 1;
188579119Sbrian        break;
188678410Sbrian      }
188778410Sbrian      break;
188878410Sbrian    case 2:
188979119Sbrian      if (strcasecmp(argp, "max") && strcasecmp(argp, "maximum")) {
189079119Sbrian        res = -1;
189179119Sbrian        break;
189279119Sbrian      }
189378410Sbrian      long_val = atol(arg->argv[arg->argn + 1]);
189478410Sbrian      change = &l->lcp.cfg.max_mru;
189578410Sbrian      if (long_val > MAX_MRU) {
189678410Sbrian        log_Printf(LogWARN, "MRU %ld: too large - maximum is %d\n", long_val,
189778410Sbrian                   MAX_MRU);
189879119Sbrian        res = 1;
189979119Sbrian        break;
190078410Sbrian      }
190178410Sbrian      break;
190278410Sbrian    default:
190379119Sbrian      res = -1;
190479119Sbrian      break;
190578410Sbrian    }
190679119Sbrian    if (res != 0)
190779119Sbrian      break;
190878410Sbrian
190937210Sbrian    if (long_val == 0)
191080385Sbrian      *change = 0;
191137210Sbrian    else if (long_val < MIN_MRU) {
191237210Sbrian      log_Printf(LogWARN, "MRU %ld: too small - min %d\n", long_val, MIN_MRU);
191379119Sbrian      res = 1;
191479119Sbrian      break;
191537210Sbrian    } else if (long_val > MAX_MRU) {
191637210Sbrian      log_Printf(LogWARN, "MRU %ld: too big - max %d\n", long_val, MAX_MRU);
191779119Sbrian      res = 1;
191879119Sbrian      break;
191937210Sbrian    } else
192078410Sbrian      *change = long_val;
192178410Sbrian    if (l->lcp.cfg.mru > *change)
192278410Sbrian      l->lcp.cfg.mru = *change;
192328679Sbrian    break;
192437210Sbrian
192536285Sbrian  case VAR_MTU:
192679163Sbrian    long_val = 0;	/* silence gcc */
192779163Sbrian    change = NULL;	/* silence gcc */
192878410Sbrian    switch(arg->argc - arg->argn) {
192978410Sbrian    case 1:
193079119Sbrian      if (argp[strspn(argp, "0123456789")] != '\0') {
193179119Sbrian        res = -1;
193279119Sbrian        break;
193379119Sbrian      }
193479119Sbrian      /*FALLTHRU*/
193578410Sbrian    case 0:
193678410Sbrian      long_val = atol(argp);
193778410Sbrian      change = &l->lcp.cfg.mtu;
193878410Sbrian      if (long_val > l->lcp.cfg.max_mtu) {
193978410Sbrian        log_Printf(LogWARN, "MTU %ld: too large - max set to %d\n", long_val,
194078410Sbrian                   l->lcp.cfg.max_mtu);
194179119Sbrian        res = 1;
194279119Sbrian        break;
194378410Sbrian      }
194478410Sbrian      break;
194578410Sbrian    case 2:
194679119Sbrian      if (strcasecmp(argp, "max") && strcasecmp(argp, "maximum")) {
194779119Sbrian        res = -1;
194879119Sbrian        break;
194979119Sbrian      }
195078410Sbrian      long_val = atol(arg->argv[arg->argn + 1]);
195178410Sbrian      change = &l->lcp.cfg.max_mtu;
195278410Sbrian      if (long_val > MAX_MTU) {
195378410Sbrian        log_Printf(LogWARN, "MTU %ld: too large - maximum is %d\n", long_val,
195478410Sbrian                   MAX_MTU);
195579119Sbrian        res = 1;
195679119Sbrian        break;
195778410Sbrian      }
195878410Sbrian      break;
195978410Sbrian    default:
196079119Sbrian      res = -1;
196179119Sbrian      break;
196278410Sbrian    }
196378410Sbrian
196479119Sbrian    if (res != 0)
196579119Sbrian      break;
196679119Sbrian
196737210Sbrian    if (long_val && long_val < MIN_MTU) {
196837210Sbrian      log_Printf(LogWARN, "MTU %ld: too small - min %d\n", long_val, MIN_MTU);
196979119Sbrian      res = 1;
197079119Sbrian      break;
197137210Sbrian    } else if (long_val > MAX_MTU) {
197237210Sbrian      log_Printf(LogWARN, "MTU %ld: too big - max %d\n", long_val, MAX_MTU);
197379119Sbrian      res = 1;
197479119Sbrian      break;
197537210Sbrian    } else
197678410Sbrian      *change = long_val;
197778410Sbrian    if (l->lcp.cfg.mtu > *change)
197878410Sbrian      l->lcp.cfg.mtu = *change;
197936285Sbrian    break;
198037210Sbrian
198136285Sbrian  case VAR_OPENMODE:
198236285Sbrian    if (strcasecmp(argp, "active") == 0)
198336285Sbrian      cx->physical->link.lcp.cfg.openmode = arg->argc > arg->argn+1 ?
198436285Sbrian        atoi(arg->argv[arg->argn+1]) : 1;
198536285Sbrian    else if (strcasecmp(argp, "passive") == 0)
198636285Sbrian      cx->physical->link.lcp.cfg.openmode = OPEN_PASSIVE;
198736285Sbrian    else {
198879119Sbrian      log_Printf(LogWARN, "%s: Invalid openmode\n", argp);
198979119Sbrian      res = 1;
199036285Sbrian    }
199136285Sbrian    break;
199237210Sbrian
199328679Sbrian  case VAR_PHONE:
199436285Sbrian    strncpy(cx->cfg.phone.list, argp, sizeof cx->cfg.phone.list - 1);
199536285Sbrian    cx->cfg.phone.list[sizeof cx->cfg.phone.list - 1] = '\0';
199638174Sbrian    cx->phone.alt = cx->phone.next = NULL;
199728679Sbrian    break;
199837210Sbrian
199928679Sbrian  case VAR_HANGUP:
200036285Sbrian    strncpy(cx->cfg.script.hangup, argp, sizeof cx->cfg.script.hangup - 1);
200136285Sbrian    cx->cfg.script.hangup[sizeof cx->cfg.script.hangup - 1] = '\0';
200228679Sbrian    break;
200337210Sbrian
200461534Sbrian  case VAR_IFQUEUE:
200561534Sbrian    long_val = atol(argp);
200661534Sbrian    arg->bundle->cfg.ifqueue = long_val < 0 ? 0 : long_val;
200761534Sbrian    break;
200861534Sbrian
200952488Sbrian  case VAR_LOGOUT:
201052488Sbrian    strncpy(cx->cfg.script.logout, argp, sizeof cx->cfg.script.logout - 1);
201152488Sbrian    cx->cfg.script.logout[sizeof cx->cfg.script.logout - 1] = '\0';
201252488Sbrian    break;
201352488Sbrian
201436285Sbrian  case VAR_IDLETIMEOUT:
201579119Sbrian    if (arg->argc > arg->argn+2) {
201679119Sbrian      log_Printf(LogWARN, "Too many idle timeout values\n");
201779119Sbrian      res = 1;
201879119Sbrian    } else if (arg->argc == arg->argn) {
201979119Sbrian      log_Printf(LogWARN, "Too few idle timeout values\n");
202079119Sbrian      res = 1;
202179119Sbrian    } else {
202249978Sbrian      int timeout, min;
202349978Sbrian
202449978Sbrian      timeout = atoi(argp);
202549978Sbrian      min = arg->argc == arg->argn + 2 ? atoi(arg->argv[arg->argn + 1]) : -1;
202649978Sbrian      bundle_SetIdleTimer(arg->bundle, timeout, min);
202749978Sbrian    }
202829549Sbrian    break;
202937210Sbrian
203036285Sbrian  case VAR_LQRPERIOD:
203137210Sbrian    long_val = atol(argp);
203237210Sbrian    if (long_val < MIN_LQRPERIOD) {
203337210Sbrian      log_Printf(LogWARN, "%ld: Invalid lqr period - min %d\n",
203437210Sbrian                 long_val, MIN_LQRPERIOD);
203579119Sbrian      res = 1;
203636285Sbrian    } else
203737210Sbrian      l->lcp.cfg.lqrperiod = long_val;
203836285Sbrian    break;
203937210Sbrian
204036285Sbrian  case VAR_LCPRETRY:
204179119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
204279119Sbrian                   &cx->physical->link.lcp.cfg.fsm.timeout,
204379119Sbrian                   &cx->physical->link.lcp.cfg.fsm.maxreq,
204479119Sbrian                   &cx->physical->link.lcp.cfg.fsm.maxtrm, DEF_FSMTRIES);
204536285Sbrian    break;
204637210Sbrian
204736285Sbrian  case VAR_CHAPRETRY:
204879119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
204979119Sbrian                   &cx->chap.auth.cfg.fsm.timeout,
205079119Sbrian                   &cx->chap.auth.cfg.fsm.maxreq, NULL, DEF_FSMAUTHTRIES);
205136285Sbrian    break;
205237210Sbrian
205336285Sbrian  case VAR_PAPRETRY:
205479119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
205579119Sbrian                   &cx->pap.cfg.fsm.timeout, &cx->pap.cfg.fsm.maxreq,
205679119Sbrian                   NULL, DEF_FSMAUTHTRIES);
205736285Sbrian    break;
205837210Sbrian
205936285Sbrian  case VAR_CCPRETRY:
206079119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
206179119Sbrian                   &l->ccp.cfg.fsm.timeout, &l->ccp.cfg.fsm.maxreq,
206279119Sbrian                   &l->ccp.cfg.fsm.maxtrm, DEF_FSMTRIES);
206336285Sbrian    break;
206437210Sbrian
206536285Sbrian  case VAR_IPCPRETRY:
206679119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
206779119Sbrian                   &arg->bundle->ncp.ipcp.cfg.fsm.timeout,
206879119Sbrian                   &arg->bundle->ncp.ipcp.cfg.fsm.maxreq,
206979119Sbrian                   &arg->bundle->ncp.ipcp.cfg.fsm.maxtrm, DEF_FSMTRIES);
207036285Sbrian    break;
207137210Sbrian
2072102855Sbrian#ifndef NOINET6
2073102558Sbrian  case VAR_IPV6CPRETRY:
2074102558Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
2075102558Sbrian                   &arg->bundle->ncp.ipv6cp.cfg.fsm.timeout,
2076102558Sbrian                   &arg->bundle->ncp.ipv6cp.cfg.fsm.maxreq,
2077102558Sbrian                   &arg->bundle->ncp.ipv6cp.cfg.fsm.maxtrm, DEF_FSMTRIES);
2078102558Sbrian    break;
2079102855Sbrian#endif
2080102558Sbrian
208136285Sbrian  case VAR_NBNS:
208236285Sbrian  case VAR_DNS:
208358044Sbrian    if (param == VAR_DNS) {
208481634Sbrian      ipaddr = arg->bundle->ncp.ipcp.cfg.ns.dns;
208581634Sbrian      ipaddr[0].s_addr = ipaddr[1].s_addr = INADDR_NONE;
208658044Sbrian    } else {
208781634Sbrian      ipaddr = arg->bundle->ncp.ipcp.cfg.ns.nbns;
208881634Sbrian      ipaddr[0].s_addr = ipaddr[1].s_addr = INADDR_ANY;
208958044Sbrian    }
209036285Sbrian
209136285Sbrian    if (arg->argc > arg->argn) {
209281634Sbrian      ncpaddr_aton(ncpaddr, &arg->bundle->ncp, arg->argv[arg->argn]);
209381634Sbrian      if (!ncpaddr_getip4(ncpaddr, ipaddr))
209481634Sbrian        return -1;
209581634Sbrian      if (arg->argc > arg->argn+1) {
209681634Sbrian        ncpaddr_aton(ncpaddr + 1, &arg->bundle->ncp, arg->argv[arg->argn + 1]);
209781634Sbrian        if (!ncpaddr_getip4(ncpaddr + 1, ipaddr + 1))
209881634Sbrian          return -1;
209981634Sbrian      }
210036285Sbrian
210181634Sbrian      if (ipaddr[0].s_addr == INADDR_ANY) {
210281634Sbrian        ipaddr[0] = ipaddr[1];
210381634Sbrian        ipaddr[1].s_addr = INADDR_ANY;
210458044Sbrian      }
210581634Sbrian      if (ipaddr[0].s_addr == INADDR_NONE) {
210681634Sbrian        ipaddr[0] = ipaddr[1];
210781634Sbrian        ipaddr[1].s_addr = INADDR_NONE;
210858044Sbrian      }
210936285Sbrian    }
211036285Sbrian    break;
211138174Sbrian
211238174Sbrian  case VAR_CALLBACK:
211338174Sbrian    cx->cfg.callback.opmask = 0;
211438174Sbrian    for (dummyint = arg->argn; dummyint < arg->argc; dummyint++) {
211538174Sbrian      if (!strcasecmp(arg->argv[dummyint], "auth"))
211638174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_AUTH);
211738174Sbrian      else if (!strcasecmp(arg->argv[dummyint], "cbcp"))
211838174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_CBCP);
211938174Sbrian      else if (!strcasecmp(arg->argv[dummyint], "e.164")) {
212038174Sbrian        if (dummyint == arg->argc - 1)
212138174Sbrian          log_Printf(LogWARN, "No E.164 arg (E.164 ignored) !\n");
212238174Sbrian        else {
212338174Sbrian          cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_E164);
212438174Sbrian          strncpy(cx->cfg.callback.msg, arg->argv[++dummyint],
212538174Sbrian                  sizeof cx->cfg.callback.msg - 1);
212638174Sbrian          cx->cfg.callback.msg[sizeof cx->cfg.callback.msg - 1] = '\0';
212738174Sbrian        }
212838174Sbrian      } else if (!strcasecmp(arg->argv[dummyint], "none"))
212938174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_NONE);
213079119Sbrian      else {
213179119Sbrian        res = -1;
213279119Sbrian        break;
213379119Sbrian      }
213438174Sbrian    }
213538174Sbrian    if (cx->cfg.callback.opmask == CALLBACK_BIT(CALLBACK_NONE))
213638174Sbrian      cx->cfg.callback.opmask = 0;
213738174Sbrian    break;
213838174Sbrian
213938174Sbrian  case VAR_CBCP:
214038174Sbrian    cx->cfg.cbcp.delay = 0;
214138174Sbrian    *cx->cfg.cbcp.phone = '\0';
214238174Sbrian    cx->cfg.cbcp.fsmretry = DEF_FSMRETRY;
214338174Sbrian    if (arg->argc > arg->argn) {
214438174Sbrian      strncpy(cx->cfg.cbcp.phone, arg->argv[arg->argn],
214538174Sbrian              sizeof cx->cfg.cbcp.phone - 1);
214638174Sbrian      cx->cfg.cbcp.phone[sizeof cx->cfg.cbcp.phone - 1] = '\0';
214738174Sbrian      if (arg->argc > arg->argn + 1) {
214838174Sbrian        cx->cfg.cbcp.delay = atoi(arg->argv[arg->argn + 1]);
214938174Sbrian        if (arg->argc > arg->argn + 2) {
215038174Sbrian          long_val = atol(arg->argv[arg->argn + 2]);
215138174Sbrian          if (long_val < MIN_FSMRETRY)
215238174Sbrian            log_Printf(LogWARN, "%ld: Invalid CBCP FSM retry period - min %d\n",
215338174Sbrian                       long_val, MIN_FSMRETRY);
215438174Sbrian          else
215538174Sbrian            cx->cfg.cbcp.fsmretry = long_val;
215638174Sbrian        }
215738174Sbrian      }
215838174Sbrian    }
215938174Sbrian    break;
216038544Sbrian
216138544Sbrian  case VAR_CHOKED:
216238544Sbrian    arg->bundle->cfg.choked.timeout = atoi(argp);
216338544Sbrian    if (arg->bundle->cfg.choked.timeout <= 0)
216438544Sbrian      arg->bundle->cfg.choked.timeout = CHOKED_TIMEOUT;
216538544Sbrian    break;
216640665Sbrian
216740665Sbrian  case VAR_SENDPIPE:
216840665Sbrian    long_val = atol(argp);
216981634Sbrian    arg->bundle->ncp.cfg.sendpipe = long_val;
217040665Sbrian    break;
217140665Sbrian
217240665Sbrian  case VAR_RECVPIPE:
217340665Sbrian    long_val = atol(argp);
217481634Sbrian    arg->bundle->ncp.cfg.recvpipe = long_val;
217540665Sbrian    break;
217643313Sbrian
217743313Sbrian#ifndef NORADIUS
217843313Sbrian  case VAR_RADIUS:
217943313Sbrian    if (!*argp)
218043313Sbrian      *arg->bundle->radius.cfg.file = '\0';
218143313Sbrian    else if (access(argp, R_OK)) {
218243313Sbrian      log_Printf(LogWARN, "%s: %s\n", argp, strerror(errno));
218379119Sbrian      res = 1;
218479119Sbrian      break;
218543313Sbrian    } else {
218643313Sbrian      strncpy(arg->bundle->radius.cfg.file, argp,
218743313Sbrian              sizeof arg->bundle->radius.cfg.file - 1);
218843313Sbrian      arg->bundle->radius.cfg.file
218943313Sbrian        [sizeof arg->bundle->radius.cfg.file - 1] = '\0';
219043313Sbrian    }
219143313Sbrian    break;
219243313Sbrian#endif
219344073Sbrian
219444073Sbrian  case VAR_CD:
219544073Sbrian    if (*argp) {
219651699Sbrian      if (strcasecmp(argp, "off")) {
219751699Sbrian        long_val = atol(argp);
219851699Sbrian        if (long_val < 0)
219951699Sbrian          long_val = 0;
220051699Sbrian        cx->physical->cfg.cd.delay = long_val;
220151699Sbrian        cx->physical->cfg.cd.necessity = argp[strlen(argp)-1] == '!' ?
220251699Sbrian          CD_REQUIRED : CD_VARIABLE;
220351699Sbrian      } else
220451699Sbrian        cx->physical->cfg.cd.necessity = CD_NOTREQUIRED;
220544073Sbrian    } else {
220653733Sbrian      cx->physical->cfg.cd.delay = 0;
220753733Sbrian      cx->physical->cfg.cd.necessity = CD_DEFAULT;
220844073Sbrian    }
220944073Sbrian    break;
221036285Sbrian
221146686Sbrian  case VAR_PARITY:
221246686Sbrian    if (arg->argc == arg->argn + 1)
221379119Sbrian      res = physical_SetParity(arg->cx->physical, argp);
221446686Sbrian    else {
221579119Sbrian      log_Printf(LogWARN, "Parity value must be odd, even or none\n");
221679119Sbrian      res = 1;
221746686Sbrian    }
221846686Sbrian    break;
22196059Samurai
222046686Sbrian  case VAR_CRTSCTS:
222146686Sbrian    if (strcasecmp(argp, "on") == 0)
222236285Sbrian      physical_SetRtsCts(arg->cx->physical, 1);
222346686Sbrian    else if (strcasecmp(argp, "off") == 0)
222436285Sbrian      physical_SetRtsCts(arg->cx->physical, 0);
222546686Sbrian    else {
222679119Sbrian      log_Printf(LogWARN, "RTS/CTS value must be on or off\n");
222779119Sbrian      res = 1;
222846686Sbrian    }
222946686Sbrian    break;
223050867Sbrian
223150867Sbrian  case VAR_URGENTPORTS:
223251048Sbrian    if (arg->argn == arg->argc) {
223381634Sbrian      ncp_SetUrgentTOS(&arg->bundle->ncp);
223481634Sbrian      ncp_ClearUrgentTcpPorts(&arg->bundle->ncp);
223581634Sbrian      ncp_ClearUrgentUdpPorts(&arg->bundle->ncp);
223651048Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "udp")) {
223781634Sbrian      ncp_SetUrgentTOS(&arg->bundle->ncp);
223851048Sbrian      if (arg->argn == arg->argc - 1)
223981634Sbrian        ncp_ClearUrgentUdpPorts(&arg->bundle->ncp);
224051048Sbrian      else for (f = arg->argn + 1; f < arg->argc; f++)
224151048Sbrian        if (*arg->argv[f] == '+')
224281634Sbrian          ncp_AddUrgentUdpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1));
224351048Sbrian        else if (*arg->argv[f] == '-')
224481634Sbrian          ncp_RemoveUrgentUdpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1));
224551048Sbrian        else {
224651048Sbrian          if (f == arg->argn)
224781634Sbrian            ncp_ClearUrgentUdpPorts(&arg->bundle->ncp);
224881634Sbrian          ncp_AddUrgentUdpPort(&arg->bundle->ncp, atoi(arg->argv[f]));
224951048Sbrian        }
225061430Sbrian    } else if (arg->argn == arg->argc - 1 &&
225161430Sbrian               !strcasecmp(arg->argv[arg->argn], "none")) {
225281634Sbrian      ncp_ClearUrgentTcpPorts(&arg->bundle->ncp);
225381634Sbrian      ncp_ClearUrgentUdpPorts(&arg->bundle->ncp);
225481634Sbrian      ncp_ClearUrgentTOS(&arg->bundle->ncp);
225551048Sbrian    } else {
225681634Sbrian      ncp_SetUrgentTOS(&arg->bundle->ncp);
225751048Sbrian      first = arg->argn;
225851048Sbrian      if (!strcasecmp(arg->argv[first], "tcp") && ++first == arg->argc)
225981634Sbrian        ncp_ClearUrgentTcpPorts(&arg->bundle->ncp);
226051048Sbrian
226151048Sbrian      for (f = first; f < arg->argc; f++)
226251048Sbrian        if (*arg->argv[f] == '+')
226381634Sbrian          ncp_AddUrgentTcpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1));
226451048Sbrian        else if (*arg->argv[f] == '-')
226581634Sbrian          ncp_RemoveUrgentTcpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1));
226651048Sbrian        else {
226751048Sbrian          if (f == first)
226881634Sbrian            ncp_ClearUrgentTcpPorts(&arg->bundle->ncp);
226981634Sbrian          ncp_AddUrgentTcpPort(&arg->bundle->ncp, atoi(arg->argv[f]));
227051048Sbrian        }
227151048Sbrian    }
227250867Sbrian    break;
227320812Sjkh  }
227446686Sbrian
227579119Sbrian  return res;
227620812Sjkh}
227720812Sjkh
227830715Sbrianstatic struct cmdtab const SetCommands[] = {
227936285Sbrian  {"accmap", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
228036285Sbrian  "accmap value", "set accmap hex-value", (const void *)VAR_ACCMAP},
228128679Sbrian  {"authkey", "key", SetVariable, LOCAL_AUTH,
228236285Sbrian  "authentication key", "set authkey|key key", (const void *)VAR_AUTHKEY},
228328679Sbrian  {"authname", NULL, SetVariable, LOCAL_AUTH,
228436285Sbrian  "authentication name", "set authname name", (const void *)VAR_AUTHNAME},
228536285Sbrian  {"autoload", NULL, SetVariable, LOCAL_AUTH,
228636285Sbrian  "auto link [de]activation", "set autoload maxtime maxload mintime minload",
228736285Sbrian  (const void *)VAR_AUTOLOAD},
228850867Sbrian  {"bandwidth", NULL, mp_SetDatalinkBandwidth, LOCAL_AUTH | LOCAL_CX,
228950867Sbrian  "datalink bandwidth", "set bandwidth value"},
229038174Sbrian  {"callback", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
229138174Sbrian  "callback control", "set callback [none|auth|cbcp|"
229238174Sbrian  "E.164 *|number[,number]...]...", (const void *)VAR_CALLBACK},
229338174Sbrian  {"cbcp", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
229498243Sbrian  "CBCP control", "set cbcp [*|phone[,phone...] [delay [timeout]]]",
229538174Sbrian  (const void *)VAR_CBCP},
229644305Sbrian  {"ccpretry", "ccpretries", SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
229744305Sbrian   "CCP retries", "set ccpretry value [attempts]", (const void *)VAR_CCPRETRY},
229844073Sbrian  {"cd", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "Carrier delay requirement",
229944073Sbrian   "set cd value[!]", (const void *)VAR_CD},
230044305Sbrian  {"chapretry", "chapretries", SetVariable, LOCAL_AUTH | LOCAL_CX,
230144305Sbrian   "CHAP retries", "set chapretry value [attempts]",
230244305Sbrian   (const void *)VAR_CHAPRETRY},
230338544Sbrian  {"choked", NULL, SetVariable, LOCAL_AUTH,
230438544Sbrian  "choked timeout", "set choked [secs]", (const void *)VAR_CHOKED},
230546686Sbrian  {"ctsrts", "crtscts", SetVariable, LOCAL_AUTH | LOCAL_CX,
230646686Sbrian   "Use hardware flow control", "set ctsrts [on|off]",
230746686Sbrian   (const char *)VAR_CRTSCTS},
230836285Sbrian  {"deflate", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
230936285Sbrian  "deflate window sizes", "set deflate out-winsize in-winsize",
231036285Sbrian  (const void *) VAR_WINSIZE},
231193418Sbrian#ifndef NODES
231267910Sbrian  {"mppe", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
231398243Sbrian  "MPPE key size and state", "set mppe [40|56|128|* [stateful|stateless|*]]",
231478411Sbrian  (const void *) VAR_MPPE},
231567910Sbrian#endif
231636285Sbrian  {"device", "line", SetVariable, LOCAL_AUTH | LOCAL_CX,
231746686Sbrian  "physical device name", "set device|line device-name[,device-name]",
231836285Sbrian  (const void *) VAR_DEVICE},
231936285Sbrian  {"dial", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
232036285Sbrian  "dialing script", "set dial chat-script", (const void *) VAR_DIAL},
232136285Sbrian  {"dns", NULL, SetVariable, LOCAL_AUTH, "Domain Name Server",
232236285Sbrian  "set dns pri-addr [sec-addr]", (const void *)VAR_DNS},
232336285Sbrian  {"enddisc", NULL, mp_SetEnddisc, LOCAL_AUTH,
232436285Sbrian  "Endpoint Discriminator", "set enddisc [IP|magic|label|psn value]"},
232536285Sbrian  {"escape", NULL, SetEscape, LOCAL_AUTH | LOCAL_CX,
232636285Sbrian  "escape characters", "set escape hex-digit ..."},
232736285Sbrian  {"filter", NULL, filter_Set, LOCAL_AUTH,
232836285Sbrian  "packet filters", "set filter alive|dial|in|out rule-no permit|deny "
232981634Sbrian  "[src_addr[/width]] [dst_addr[/width]] [proto "
233048142Sbrian  "[src [lt|eq|gt port]] [dst [lt|eq|gt port]] [estab] [syn] [finrst]]"},
233136285Sbrian  {"hangup", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
233236285Sbrian  "hangup script", "set hangup chat-script", (const void *) VAR_HANGUP},
233336285Sbrian  {"ifaddr", NULL, SetInterfaceAddr, LOCAL_AUTH, "destination address",
233431343Sbrian  "set ifaddr [src-addr [dst-addr [netmask [trg-addr]]]]"},
233561534Sbrian  {"ifqueue", NULL, SetVariable, LOCAL_AUTH, "interface queue",
233661534Sbrian  "set ifqueue packets", (const void *)VAR_IFQUEUE},
233744305Sbrian  {"ipcpretry", "ipcpretries", SetVariable, LOCAL_AUTH, "IPCP retries",
233844305Sbrian   "set ipcpretry value [attempts]", (const void *)VAR_IPCPRETRY},
2339102558Sbrian  {"ipv6cpretry", "ipv6cpretries", SetVariable, LOCAL_AUTH, "IPV6CP retries",
2340102558Sbrian   "set ipv6cpretry value [attempts]", (const void *)VAR_IPV6CPRETRY},
234144305Sbrian  {"lcpretry", "lcpretries", SetVariable, LOCAL_AUTH | LOCAL_CX, "LCP retries",
234244305Sbrian   "set lcpretry value [attempts]", (const void *)VAR_LCPRETRY},
234336712Sbrian  {"log", NULL, log_SetLevel, LOCAL_AUTH, "log level",
234467916Sbrian  "set log [local] [+|-]all|async|cbcp|ccp|chat|command|connect|debug|dns|hdlc|"
234558033Sbrian  "id0|ipcp|lcp|lqm|phase|physical|sync|tcp/ip|timer|tun..."},
234636285Sbrian  {"login", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
234736285Sbrian  "login script", "set login chat-script", (const void *) VAR_LOGIN},
234852488Sbrian  {"logout", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
234952488Sbrian  "logout script", "set logout chat-script", (const void *) VAR_LOGOUT},
235036285Sbrian  {"lqrperiod", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
235136285Sbrian  "LQR period", "set lqrperiod value", (const void *)VAR_LQRPERIOD},
235236285Sbrian  {"mode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "mode value",
235336285Sbrian  "set mode interactive|auto|ddial|background", (const void *)VAR_MODE},
235436285Sbrian  {"mrru", NULL, SetVariable, LOCAL_AUTH, "MRRU value",
235536285Sbrian  "set mrru value", (const void *)VAR_MRRU},
235696038Sbrian  {"mru", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
235778410Sbrian  "MRU value", "set mru [max[imum]] [value]", (const void *)VAR_MRU},
235878410Sbrian  {"mtu", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
235978410Sbrian  "interface MTU value", "set mtu [max[imum]] [value]", (const void *)VAR_MTU},
236036285Sbrian  {"nbns", NULL, SetVariable, LOCAL_AUTH, "NetBIOS Name Server",
236136285Sbrian  "set nbns pri-addr [sec-addr]", (const void *)VAR_NBNS},
236236285Sbrian  {"openmode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "open mode",
236336285Sbrian  "set openmode active|passive [secs]", (const void *)VAR_OPENMODE},
236444305Sbrian  {"papretry", "papretries", SetVariable, LOCAL_AUTH | LOCAL_CX, "PAP retries",
236544305Sbrian   "set papretry value [attempts]", (const void *)VAR_PAPRETRY},
236646686Sbrian  {"parity", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "serial parity",
236746686Sbrian   "set parity [odd|even|none]", (const void *)VAR_PARITY},
236836285Sbrian  {"phone", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "telephone number(s)",
236936285Sbrian  "set phone phone1[:phone2[...]]", (const void *)VAR_PHONE},
237040679Sbrian  {"proctitle", "title", SetProcTitle, LOCAL_AUTH,
237140679Sbrian  "Process title", "set proctitle [value]"},
237243313Sbrian#ifndef NORADIUS
237343313Sbrian  {"radius", NULL, SetVariable, LOCAL_AUTH,
237443313Sbrian  "RADIUS Config", "set radius cfgfile", (const void *)VAR_RADIUS},
237543313Sbrian#endif
237636285Sbrian  {"reconnect", NULL, datalink_SetReconnect, LOCAL_AUTH | LOCAL_CX,
237736285Sbrian  "Reconnect timeout", "set reconnect value ntries"},
237840665Sbrian  {"recvpipe", NULL, SetVariable, LOCAL_AUTH,
237940665Sbrian  "RECVPIPE value", "set recvpipe value", (const void *)VAR_RECVPIPE},
238036285Sbrian  {"redial", NULL, datalink_SetRedial, LOCAL_AUTH | LOCAL_CX,
238144468Sbrian  "Redial timeout", "set redial secs[+inc[-incmax]][.next] [attempts]"},
238240665Sbrian  {"sendpipe", NULL, SetVariable, LOCAL_AUTH,
238340665Sbrian  "SENDPIPE value", "set sendpipe value", (const void *)VAR_SENDPIPE},
238471657Sbrian  {"server", "socket", SetServer, LOCAL_AUTH, "diagnostic port",
238571657Sbrian  "set server|socket TcpPort|LocalName|none|open|closed [password [mask]]"},
238636285Sbrian  {"speed", NULL, SetModemSpeed, LOCAL_AUTH | LOCAL_CX,
238746686Sbrian  "physical speed", "set speed value|sync"},
238836285Sbrian  {"stopped", NULL, SetStoppedTimeout, LOCAL_AUTH | LOCAL_CX,
238936285Sbrian  "STOPPED timeouts", "set stopped [LCPseconds [CCPseconds]]"},
239036285Sbrian  {"timeout", NULL, SetVariable, LOCAL_AUTH, "Idle timeout",
239136285Sbrian  "set timeout idletime", (const void *)VAR_IDLETIMEOUT},
239251048Sbrian  {"urgent", NULL, SetVariable, LOCAL_AUTH, "urgent ports",
239351048Sbrian  "set urgent [tcp|udp] [+|-]port...", (const void *)VAR_URGENTPORTS},
239436285Sbrian  {"vj", NULL, ipcp_vjset, LOCAL_AUTH,
239536285Sbrian  "vj values", "set vj slots|slotcomp [value]"},
239628679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
239731343Sbrian  "Display this message", "set help|? [command]", SetCommands},
239828679Sbrian  {NULL, NULL, NULL},
23996059Samurai};
24006059Samurai
24016059Samuraistatic int
240231343SbrianSetCommand(struct cmdargs const *arg)
24036059Samurai{
240436285Sbrian  if (arg->argc > arg->argn)
240536285Sbrian    FindExec(arg->bundle, SetCommands, arg->argc, arg->argn, arg->argv,
240636285Sbrian             arg->prompt, arg->cx);
240736285Sbrian  else if (arg->prompt)
240836285Sbrian    prompt_Printf(arg->prompt, "Use `set ?' to get a list or `set ? <var>' for"
240958044Sbrian	          " syntax help.\n");
24106059Samurai  else
241136285Sbrian    log_Printf(LogWARN, "set command must have arguments\n");
241226516Sbrian
241326516Sbrian  return 0;
24146059Samurai}
24156059Samurai
24166059Samuraistatic int
241731343SbrianAddCommand(struct cmdargs const *arg)
24186059Samurai{
241981634Sbrian  struct ncpaddr gw;
242081634Sbrian  struct ncprange dest;
242181634Sbrian  struct in_addr host;
2422112673Sume#ifndef NOINET6
2423112673Sume  struct in6_addr host6;
2424112673Sume#endif
242581634Sbrian  int dest_default, gw_arg, addrs;
24266059Samurai
242736285Sbrian  if (arg->argc != arg->argn+3 && arg->argc != arg->argn+2)
242831598Sbrian    return -1;
242931598Sbrian
243036285Sbrian  addrs = 0;
243181634Sbrian  dest_default = 0;
243281634Sbrian  if (arg->argc == arg->argn + 2) {
243336285Sbrian    if (!strcasecmp(arg->argv[arg->argn], "default"))
243481634Sbrian      dest_default = 1;
243531598Sbrian    else {
243681634Sbrian      if (!ncprange_aton(&dest, &arg->bundle->ncp, arg->argv[arg->argn]))
243736285Sbrian        return -1;
243836285Sbrian      if (!strncasecmp(arg->argv[arg->argn], "MYADDR", 6))
243936285Sbrian        addrs = ROUTE_DSTMYADDR;
244081634Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "MYADDR6", 7))
244181634Sbrian        addrs = ROUTE_DSTMYADDR6;
244236285Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "HISADDR", 7))
244336285Sbrian        addrs = ROUTE_DSTHISADDR;
244481634Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "HISADDR6", 8))
244581634Sbrian        addrs = ROUTE_DSTHISADDR6;
244658044Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "DNS0", 4))
244758044Sbrian        addrs = ROUTE_DSTDNS0;
244858044Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "DNS1", 4))
244958044Sbrian        addrs = ROUTE_DSTDNS1;
245031598Sbrian    }
245181634Sbrian    gw_arg = 1;
245234536Sbrian  } else {
245336285Sbrian    if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
245436285Sbrian      addrs = ROUTE_DSTMYADDR;
245581634Sbrian      host = arg->bundle->ncp.ipcp.my_ip;
245636285Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
245736285Sbrian      addrs = ROUTE_DSTHISADDR;
245881634Sbrian      host = arg->bundle->ncp.ipcp.peer_ip;
245958044Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "DNS0") == 0) {
246058044Sbrian      addrs = ROUTE_DSTDNS0;
246181634Sbrian      host = arg->bundle->ncp.ipcp.ns.dns[0];
246258044Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "DNS1") == 0) {
246358044Sbrian      addrs = ROUTE_DSTDNS1;
246481634Sbrian      host = arg->bundle->ncp.ipcp.ns.dns[1];
246565263Sbrian    } else {
246681634Sbrian      host = GetIpAddr(arg->argv[arg->argn]);
246781634Sbrian      if (host.s_addr == INADDR_NONE) {
246865263Sbrian        log_Printf(LogWARN, "%s: Invalid destination address\n",
246965263Sbrian                   arg->argv[arg->argn]);
247065263Sbrian        return -1;
247165263Sbrian      }
247265263Sbrian    }
247381634Sbrian    ncprange_setip4(&dest, host, GetIpAddr(arg->argv[arg->argn + 1]));
247481634Sbrian    gw_arg = 2;
24756059Samurai  }
247636285Sbrian
247781634Sbrian  if (strcasecmp(arg->argv[arg->argn + gw_arg], "HISADDR") == 0) {
247881634Sbrian    ncpaddr_setip4(&gw, arg->bundle->ncp.ipcp.peer_ip);
247936285Sbrian    addrs |= ROUTE_GWHISADDR;
248081634Sbrian#ifndef NOINET6
248181897Sbrian  } else if (strcasecmp(arg->argv[arg->argn + gw_arg], "HISADDR6") == 0) {
2482112673Sume    if (!ncpaddr_getip6(&arg->bundle->ncp.ipv6cp.hisaddr, &host6))
2483112673Sume      memset(&host6, '\0', sizeof host6);
2484112673Sume    ncpaddr_setip6(&gw, &host6);
248581634Sbrian    addrs |= ROUTE_GWHISADDR6;
248681634Sbrian#endif
248765263Sbrian  } else {
248881634Sbrian    if (!ncpaddr_aton(&gw, &arg->bundle->ncp, arg->argv[arg->argn + gw_arg])) {
248965263Sbrian      log_Printf(LogWARN, "%s: Invalid gateway address\n",
249081634Sbrian                 arg->argv[arg->argn + gw_arg]);
249165263Sbrian      return -1;
249265263Sbrian    }
249365263Sbrian  }
249436285Sbrian
249581634Sbrian  if (dest_default)
249681634Sbrian    ncprange_setdefault(&dest, ncpaddr_family(&gw));
249781634Sbrian
249881634Sbrian  if (rt_Set(arg->bundle, RTM_ADD, &dest, &gw, arg->cmd->args ? 1 : 0,
249981634Sbrian             ((addrs & ROUTE_GWHISADDR) || (addrs & ROUTE_GWHISADDR6)) ? 1 : 0)
250043313Sbrian      && addrs != ROUTE_STATIC)
250181634Sbrian    route_Add(&arg->bundle->ncp.route, addrs, &dest, &gw);
250236285Sbrian
250331598Sbrian  return 0;
25046059Samurai}
25056059Samurai
25066059Samuraistatic int
250731343SbrianDeleteCommand(struct cmdargs const *arg)
25086059Samurai{
250981634Sbrian  struct ncprange dest;
251036285Sbrian  int addrs;
25116059Samurai
251236285Sbrian  if (arg->argc == arg->argn+1) {
251336285Sbrian    if(strcasecmp(arg->argv[arg->argn], "all") == 0) {
251436285Sbrian      route_IfDelete(arg->bundle, 0);
251581634Sbrian      route_DeleteAll(&arg->bundle->ncp.route);
251636285Sbrian    } else {
251736285Sbrian      addrs = 0;
251836285Sbrian      if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
251981634Sbrian        ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.my_ip);
252036285Sbrian        addrs = ROUTE_DSTMYADDR;
252181634Sbrian#ifndef NOINET6
252281897Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "MYADDR6") == 0) {
252381634Sbrian        ncprange_sethost(&dest, &arg->bundle->ncp.ipv6cp.myaddr);
252481634Sbrian        addrs = ROUTE_DSTMYADDR6;
252581634Sbrian#endif
252636285Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
252781634Sbrian        ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.peer_ip);
252836285Sbrian        addrs = ROUTE_DSTHISADDR;
252981634Sbrian#ifndef NOINET6
253081897Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "HISADDR6") == 0) {
253181634Sbrian        ncprange_sethost(&dest, &arg->bundle->ncp.ipv6cp.hisaddr);
253281634Sbrian        addrs = ROUTE_DSTHISADDR6;
253381634Sbrian#endif
253458044Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "DNS0") == 0) {
253581634Sbrian        ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.ns.dns[0]);
253658044Sbrian        addrs = ROUTE_DSTDNS0;
253758044Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "DNS1") == 0) {
253881634Sbrian        ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.ns.dns[1]);
253958044Sbrian        addrs = ROUTE_DSTDNS1;
254036285Sbrian      } else {
254181634Sbrian        ncprange_aton(&dest, &arg->bundle->ncp, arg->argv[arg->argn]);
254236285Sbrian        addrs = ROUTE_STATIC;
254336285Sbrian      }
254481634Sbrian      rt_Set(arg->bundle, RTM_DELETE, &dest, NULL, arg->cmd->args ? 1 : 0, 0);
254581634Sbrian      route_Delete(&arg->bundle->ncp.route, addrs, &dest);
254631598Sbrian    }
254734536Sbrian  } else
254826516Sbrian    return -1;
254926516Sbrian
255026516Sbrian  return 0;
25516059Samurai}
25526059Samurai
255350059Sbrian#ifndef NONAT
255426031Sbrianstatic int
255558867SbrianNatEnable(struct cmdargs const *arg)
255626031Sbrian{
255736285Sbrian  if (arg->argc == arg->argn+1) {
255836285Sbrian    if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
255950059Sbrian      if (!arg->bundle->NatEnabled) {
256046686Sbrian        if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED)
256146686Sbrian          PacketAliasSetAddress(arg->bundle->ncp.ipcp.my_ip);
256250059Sbrian        arg->bundle->NatEnabled = 1;
256346686Sbrian      }
256437191Sbrian      return 0;
256536285Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "no") == 0) {
256650059Sbrian      arg->bundle->NatEnabled = 0;
256740561Sbrian      arg->bundle->cfg.opt &= ~OPT_IFACEALIAS;
256840561Sbrian      /* Don't iface_Clear() - there may be manually configured addresses */
256926516Sbrian      return 0;
257026142Sbrian    }
257135449Sbrian  }
257236285Sbrian
257326516Sbrian  return -1;
257426031Sbrian}
257526031Sbrian
257626031Sbrian
257726031Sbrianstatic int
257858867SbrianNatOption(struct cmdargs const *arg)
257926031Sbrian{
258038559Sbrian  long param = (long)arg->cmd->args;
258138559Sbrian
258236285Sbrian  if (arg->argc == arg->argn+1) {
258336285Sbrian    if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
258450059Sbrian      if (arg->bundle->NatEnabled) {
258537191Sbrian	PacketAliasSetMode(param, param);
258628679Sbrian	return 0;
258728679Sbrian      }
258850059Sbrian      log_Printf(LogWARN, "nat not enabled\n");
258936285Sbrian    } else if (strcmp(arg->argv[arg->argn], "no") == 0) {
259050059Sbrian      if (arg->bundle->NatEnabled) {
259137191Sbrian	PacketAliasSetMode(0, param);
259228679Sbrian	return 0;
259328679Sbrian      }
259450059Sbrian      log_Printf(LogWARN, "nat not enabled\n");
259528679Sbrian    }
259635449Sbrian  }
259728679Sbrian  return -1;
259826031Sbrian}
259950059Sbrian#endif /* #ifndef NONAT */
260031121Sbrian
260131121Sbrianstatic int
260236285SbrianLinkCommand(struct cmdargs const *arg)
260336285Sbrian{
260436285Sbrian  if (arg->argc > arg->argn+1) {
260536285Sbrian    char namelist[LINE_LEN];
260636285Sbrian    struct datalink *cx;
260736285Sbrian    char *name;
260836285Sbrian    int result = 0;
260936285Sbrian
261036285Sbrian    if (!strcmp(arg->argv[arg->argn], "*")) {
261136285Sbrian      struct datalink *dl;
261236285Sbrian
261336285Sbrian      cx = arg->bundle->links;
261436285Sbrian      while (cx) {
261536285Sbrian        /* Watch it, the command could be a ``remove'' */
261636285Sbrian        dl = cx->next;
261736285Sbrian        FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
261836285Sbrian                 arg->prompt, cx);
261936285Sbrian        for (cx = arg->bundle->links; cx; cx = cx->next)
262036285Sbrian          if (cx == dl)
262136285Sbrian            break;		/* Pointer's still valid ! */
262236285Sbrian      }
262336285Sbrian    } else {
262436285Sbrian      strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
262536285Sbrian      namelist[sizeof namelist - 1] = '\0';
262636285Sbrian      for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
262736285Sbrian        if (!bundle2datalink(arg->bundle, name)) {
262836285Sbrian          log_Printf(LogWARN, "link: %s: Invalid link name\n", name);
262936285Sbrian          return 1;
263036285Sbrian        }
263136285Sbrian
263236285Sbrian      strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
263336285Sbrian      namelist[sizeof namelist - 1] = '\0';
263436285Sbrian      for(name = strtok(namelist, ", "); name; name = strtok(NULL,", ")) {
263536285Sbrian        cx = bundle2datalink(arg->bundle, name);
263636285Sbrian        if (cx)
263736285Sbrian          FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
263836285Sbrian                   arg->prompt, cx);
263936285Sbrian        else {
264036285Sbrian          log_Printf(LogWARN, "link: %s: Invalidated link name !\n", name);
264136285Sbrian          result++;
264236285Sbrian        }
264336285Sbrian      }
264436285Sbrian    }
264536285Sbrian    return result;
264636285Sbrian  }
264736285Sbrian
264895258Sdes  log_Printf(LogWARN, "usage: %s\n", arg->cmd->syntax);
264936285Sbrian  return 2;
265036285Sbrian}
265136285Sbrian
265236285Sbrianstruct link *
265336285Sbriancommand_ChooseLink(struct cmdargs const *arg)
265436285Sbrian{
265536285Sbrian  if (arg->cx)
265636285Sbrian    return &arg->cx->physical->link;
265737210Sbrian  else if (!arg->bundle->ncp.mp.cfg.mrru) {
265836285Sbrian    struct datalink *dl = bundle2datalink(arg->bundle, NULL);
265937210Sbrian    if (dl)
266037210Sbrian      return &dl->physical->link;
266136285Sbrian  }
266237210Sbrian  return &arg->bundle->ncp.mp.link;
266336285Sbrian}
266436285Sbrian
266536285Sbrianstatic const char *
266636285Sbrianident_cmd(const char *cmd, unsigned *keep, unsigned *add)
266736285Sbrian{
266836285Sbrian  const char *result;
266936285Sbrian
267036285Sbrian  switch (*cmd) {
267136285Sbrian    case 'A':
267236285Sbrian    case 'a':
267336285Sbrian      result = "accept";
267436285Sbrian      *keep = NEG_MYMASK;
267536285Sbrian      *add = NEG_ACCEPTED;
267636285Sbrian      break;
267736285Sbrian    case 'D':
267836285Sbrian    case 'd':
267936285Sbrian      switch (cmd[1]) {
268036285Sbrian        case 'E':
268136285Sbrian        case 'e':
268236285Sbrian          result = "deny";
268336285Sbrian          *keep = NEG_MYMASK;
268436285Sbrian          *add = 0;
268536285Sbrian          break;
268636285Sbrian        case 'I':
268736285Sbrian        case 'i':
268836285Sbrian          result = "disable";
268936285Sbrian          *keep = NEG_HISMASK;
269036285Sbrian          *add = 0;
269136285Sbrian          break;
269236285Sbrian        default:
269336285Sbrian          return NULL;
269436285Sbrian      }
269536285Sbrian      break;
269636285Sbrian    case 'E':
269736285Sbrian    case 'e':
269836285Sbrian      result = "enable";
269936285Sbrian      *keep = NEG_HISMASK;
270036285Sbrian      *add = NEG_ENABLED;
270136285Sbrian      break;
270236285Sbrian    default:
270336285Sbrian      return NULL;
270436285Sbrian  }
270536285Sbrian
270636285Sbrian  return result;
270736285Sbrian}
270836285Sbrian
270936285Sbrianstatic int
271036285SbrianOptSet(struct cmdargs const *arg)
271136285Sbrian{
271237574Sbrian  int bit = (int)(long)arg->cmd->args;
271336285Sbrian  unsigned keep;			/* Keep these bits */
271436285Sbrian  unsigned add;				/* Add these bits */
271536285Sbrian
271681697Sbrian  if (ident_cmd(arg->argv[arg->argn - 2], &keep, &add) == NULL)
271736285Sbrian    return 1;
271836285Sbrian
271981885Sbrian#ifndef NOINET6
272081697Sbrian  if (add == NEG_ENABLED && bit == OPT_IPV6CP && !probe.ipv6_available) {
272181697Sbrian    log_Printf(LogWARN, "IPv6 is not available on this machine\n");
272281697Sbrian    return 1;
272381697Sbrian  }
272481885Sbrian#endif
272581697Sbrian
272636285Sbrian  if (add)
272736285Sbrian    arg->bundle->cfg.opt |= bit;
272836285Sbrian  else
272936285Sbrian    arg->bundle->cfg.opt &= ~bit;
273081697Sbrian
273136285Sbrian  return 0;
273236285Sbrian}
273336285Sbrian
273436285Sbrianstatic int
273540561SbrianIfaceAliasOptSet(struct cmdargs const *arg)
273640561Sbrian{
273740561Sbrian  unsigned save = arg->bundle->cfg.opt;
273840561Sbrian  int result = OptSet(arg);
273940561Sbrian
274040561Sbrian  if (result == 0)
274150059Sbrian    if (Enabled(arg->bundle, OPT_IFACEALIAS) && !arg->bundle->NatEnabled) {
274240561Sbrian      arg->bundle->cfg.opt = save;
274350059Sbrian      log_Printf(LogWARN, "Cannot enable iface-alias without NAT\n");
274440561Sbrian      result = 2;
274540561Sbrian    }
274640561Sbrian
274740561Sbrian  return result;
274840561Sbrian}
274940561Sbrian
275040561Sbrianstatic int
275136285SbrianNegotiateSet(struct cmdargs const *arg)
275236285Sbrian{
275337210Sbrian  long param = (long)arg->cmd->args;
275436285Sbrian  struct link *l = command_ChooseLink(arg);	/* LOCAL_CX_OPT uses this */
275536285Sbrian  struct datalink *cx = arg->cx;	/* LOCAL_CX uses this */
275636285Sbrian  const char *cmd;
275736285Sbrian  unsigned keep;			/* Keep these bits */
275836285Sbrian  unsigned add;				/* Add these bits */
275936285Sbrian
276036285Sbrian  if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL)
276136285Sbrian    return 1;
276236285Sbrian
276336285Sbrian  if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
276436285Sbrian    log_Printf(LogWARN, "%s %s: No context (use the `link' command)\n",
276536285Sbrian              cmd, arg->cmd->name);
276636285Sbrian    return 2;
276736285Sbrian  } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
276836285Sbrian    log_Printf(LogWARN, "%s %s: Redundant context (%s) ignored\n",
276936285Sbrian              cmd, arg->cmd->name, cx->name);
277036285Sbrian    cx = NULL;
277136285Sbrian  }
277236285Sbrian
277336285Sbrian  switch (param) {
277436285Sbrian    case NEG_ACFCOMP:
277536285Sbrian      cx->physical->link.lcp.cfg.acfcomp &= keep;
277636285Sbrian      cx->physical->link.lcp.cfg.acfcomp |= add;
277736285Sbrian      break;
277844106Sbrian    case NEG_CHAP05:
277944106Sbrian      cx->physical->link.lcp.cfg.chap05 &= keep;
278044106Sbrian      cx->physical->link.lcp.cfg.chap05 |= add;
278136285Sbrian      break;
278293418Sbrian#ifndef NODES
278344106Sbrian    case NEG_CHAP80:
278444106Sbrian      cx->physical->link.lcp.cfg.chap80nt &= keep;
278544106Sbrian      cx->physical->link.lcp.cfg.chap80nt |= add;
278644106Sbrian      break;
278744106Sbrian    case NEG_CHAP80LM:
278844106Sbrian      cx->physical->link.lcp.cfg.chap80lm &= keep;
278944106Sbrian      cx->physical->link.lcp.cfg.chap80lm |= add;
279044106Sbrian      break;
279167910Sbrian    case NEG_CHAP81:
279267910Sbrian      cx->physical->link.lcp.cfg.chap81 &= keep;
279367910Sbrian      cx->physical->link.lcp.cfg.chap81 |= add;
279467910Sbrian      break;
279567910Sbrian    case NEG_MPPE:
279667910Sbrian      l->ccp.cfg.neg[CCP_NEG_MPPE] &= keep;
279767910Sbrian      l->ccp.cfg.neg[CCP_NEG_MPPE] |= add;
279867910Sbrian      break;
279944106Sbrian#endif
280036285Sbrian    case NEG_DEFLATE:
280136285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE] &= keep;
280236285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE] |= add;
280336285Sbrian      break;
280436285Sbrian    case NEG_DNS:
280536285Sbrian      arg->bundle->ncp.ipcp.cfg.ns.dns_neg &= keep;
280636285Sbrian      arg->bundle->ncp.ipcp.cfg.ns.dns_neg |= add;
280736285Sbrian      break;
280847858Sbrian    case NEG_ENDDISC:
280947858Sbrian      arg->bundle->ncp.mp.cfg.negenddisc &= keep;
281047858Sbrian      arg->bundle->ncp.mp.cfg.negenddisc |= add;
281147858Sbrian      break;
281236285Sbrian    case NEG_LQR:
281336285Sbrian      cx->physical->link.lcp.cfg.lqr &= keep;
281436285Sbrian      cx->physical->link.lcp.cfg.lqr |= add;
281536285Sbrian      break;
281636285Sbrian    case NEG_PAP:
281736285Sbrian      cx->physical->link.lcp.cfg.pap &= keep;
281836285Sbrian      cx->physical->link.lcp.cfg.pap |= add;
281936285Sbrian      break;
282036285Sbrian    case NEG_PPPDDEFLATE:
282136285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE24] &= keep;
282236285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE24] |= add;
282336285Sbrian      break;
282436285Sbrian    case NEG_PRED1:
282536285Sbrian      l->ccp.cfg.neg[CCP_NEG_PRED1] &= keep;
282636285Sbrian      l->ccp.cfg.neg[CCP_NEG_PRED1] |= add;
282736285Sbrian      break;
282836285Sbrian    case NEG_PROTOCOMP:
282936285Sbrian      cx->physical->link.lcp.cfg.protocomp &= keep;
283036285Sbrian      cx->physical->link.lcp.cfg.protocomp |= add;
283136285Sbrian      break;
283236285Sbrian    case NEG_SHORTSEQ:
283340622Sbrian      switch (bundle_Phase(arg->bundle)) {
283440622Sbrian        case PHASE_DEAD:
283540622Sbrian          break;
283640622Sbrian        case PHASE_ESTABLISH:
283740622Sbrian          /* Make sure none of our links are DATALINK_LCP or greater */
283840622Sbrian          if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) {
283940622Sbrian            log_Printf(LogWARN, "shortseq: Only changable before"
284040622Sbrian                       " LCP negotiations\n");
284140622Sbrian            return 1;
284240622Sbrian          }
284340622Sbrian          break;
284440622Sbrian        default:
284540622Sbrian          log_Printf(LogWARN, "shortseq: Only changable at phase"
284640622Sbrian                     " DEAD/ESTABLISH\n");
284740622Sbrian          return 1;
284836285Sbrian      }
284940622Sbrian      arg->bundle->ncp.mp.cfg.shortseq &= keep;
285040622Sbrian      arg->bundle->ncp.mp.cfg.shortseq |= add;
285136285Sbrian      break;
285236285Sbrian    case NEG_VJCOMP:
285336285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.neg &= keep;
285436285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.neg |= add;
285536285Sbrian      break;
285636285Sbrian  }
285736285Sbrian
285836285Sbrian  return 0;
285936285Sbrian}
286036285Sbrian
286136285Sbrianstatic struct cmdtab const NegotiateCommands[] = {
286262778Sbrian  {"filter-decapsulation", NULL, OptSet, LOCAL_AUTH,
286362778Sbrian  "filter on PPPoUDP payloads", "disable|enable",
286462778Sbrian  (const void *)OPT_FILTERDECAP},
2865112659Sbrian  {"force-scripts", NULL, OptSet, LOCAL_AUTH,
2866112659Sbrian   "Force execution of the configured chat scripts", "disable|enable",
2867112659Sbrian   (const void *)OPT_FORCE_SCRIPTS},
286836285Sbrian  {"idcheck", NULL, OptSet, LOCAL_AUTH, "Check FSM reply ids",
286936285Sbrian  "disable|enable", (const void *)OPT_IDCHECK},
287040666Sbrian  {"iface-alias", NULL, IfaceAliasOptSet, LOCAL_AUTH,
287162778Sbrian  "retain interface addresses", "disable|enable",
287262778Sbrian  (const void *)OPT_IFACEALIAS},
287381634Sbrian#ifndef NOINET6
287481634Sbrian  {"ipcp", NULL, OptSet, LOCAL_AUTH, "IP Network Control Protocol",
287581634Sbrian  "disable|enable", (const void *)OPT_IPCP},
287681634Sbrian  {"ipv6cp", NULL, OptSet, LOCAL_AUTH, "IPv6 Network Control Protocol",
287781634Sbrian  "disable|enable", (const void *)OPT_IPV6CP},
287881634Sbrian#endif
287947689Sbrian  {"keep-session", NULL, OptSet, LOCAL_AUTH, "Retain device session leader",
288047689Sbrian  "disable|enable", (const void *)OPT_KEEPSESSION},
288136285Sbrian  {"loopback", NULL, OptSet, LOCAL_AUTH, "Loop packets for local iface",
288236285Sbrian  "disable|enable", (const void *)OPT_LOOPBACK},
288336285Sbrian  {"passwdauth", NULL, OptSet, LOCAL_AUTH, "Use passwd file",
288436285Sbrian  "disable|enable", (const void *)OPT_PASSWDAUTH},
288540665Sbrian  {"proxy", NULL, OptSet, LOCAL_AUTH, "Create a proxy ARP entry",
288636285Sbrian  "disable|enable", (const void *)OPT_PROXY},
288740665Sbrian  {"proxyall", NULL, OptSet, LOCAL_AUTH, "Proxy ARP for all remote hosts",
288840665Sbrian  "disable|enable", (const void *)OPT_PROXYALL},
288936285Sbrian  {"sroutes", NULL, OptSet, LOCAL_AUTH, "Use sticky routes",
289036285Sbrian  "disable|enable", (const void *)OPT_SROUTES},
289169303Sbrian  {"tcpmssfixup", "mssfixup", OptSet, LOCAL_AUTH, "Modify MSS options",
289269303Sbrian  "disable|enable", (const void *)OPT_TCPMSSFIXUP},
289336285Sbrian  {"throughput", NULL, OptSet, LOCAL_AUTH, "Rolling throughput",
289436285Sbrian  "disable|enable", (const void *)OPT_THROUGHPUT},
289536285Sbrian  {"utmp", NULL, OptSet, LOCAL_AUTH, "Log connections in utmp",
289636285Sbrian  "disable|enable", (const void *)OPT_UTMP},
289736285Sbrian
289881634Sbrian#ifndef NOINET6
2899112659Sbrian#define OPT_MAX 14	/* accept/deny allowed below and not above */
290081634Sbrian#else
2901112659Sbrian#define OPT_MAX 12
290281634Sbrian#endif
290336285Sbrian
290436285Sbrian  {"acfcomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
290536285Sbrian  "Address & Control field compression", "accept|deny|disable|enable",
290636285Sbrian  (const void *)NEG_ACFCOMP},
290744106Sbrian  {"chap", "chap05", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
290836285Sbrian  "Challenge Handshake Authentication Protocol", "accept|deny|disable|enable",
290944106Sbrian  (const void *)NEG_CHAP05},
291093418Sbrian#ifndef NODES
291144106Sbrian  {"mschap", "chap80nt", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
291244106Sbrian  "Microsoft (NT) CHAP", "accept|deny|disable|enable",
291344106Sbrian  (const void *)NEG_CHAP80},
291444106Sbrian  {"LANMan", "chap80lm", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
291544106Sbrian  "Microsoft (NT) CHAP", "accept|deny|disable|enable",
291644106Sbrian  (const void *)NEG_CHAP80LM},
291767910Sbrian  {"mschapv2", "chap81", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
291867910Sbrian  "Microsoft CHAP v2", "accept|deny|disable|enable",
291967910Sbrian  (const void *)NEG_CHAP81},
292067910Sbrian  {"mppe", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
292167910Sbrian  "MPPE encryption", "accept|deny|disable|enable",
292267910Sbrian  (const void *)NEG_MPPE},
292344106Sbrian#endif
292436285Sbrian  {"deflate", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
292536285Sbrian  "Deflate compression", "accept|deny|disable|enable",
292636285Sbrian  (const void *)NEG_DEFLATE},
292736285Sbrian  {"deflate24", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
292836285Sbrian  "Deflate (type 24) compression", "accept|deny|disable|enable",
292936285Sbrian  (const void *)NEG_PPPDDEFLATE},
293036285Sbrian  {"dns", NULL, NegotiateSet, LOCAL_AUTH,
293136285Sbrian  "DNS specification", "accept|deny|disable|enable", (const void *)NEG_DNS},
293247858Sbrian  {"enddisc", NULL, NegotiateSet, LOCAL_AUTH, "ENDDISC negotiation",
293347858Sbrian  "accept|deny|disable|enable", (const void *)NEG_ENDDISC},
293436285Sbrian  {"lqr", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
293536285Sbrian  "Link Quality Reports", "accept|deny|disable|enable",
293636285Sbrian  (const void *)NEG_LQR},
293736285Sbrian  {"pap", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
293836285Sbrian  "Password Authentication protocol", "accept|deny|disable|enable",
293936285Sbrian  (const void *)NEG_PAP},
294036285Sbrian  {"pred1", "predictor1", NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
294136285Sbrian  "Predictor 1 compression", "accept|deny|disable|enable",
294236285Sbrian  (const void *)NEG_PRED1},
294336285Sbrian  {"protocomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
294436285Sbrian  "Protocol field compression", "accept|deny|disable|enable",
294536285Sbrian  (const void *)NEG_PROTOCOMP},
294636285Sbrian  {"shortseq", NULL, NegotiateSet, LOCAL_AUTH,
294736285Sbrian  "MP Short Sequence Numbers", "accept|deny|disable|enable",
294836285Sbrian  (const void *)NEG_SHORTSEQ},
294936285Sbrian  {"vjcomp", NULL, NegotiateSet, LOCAL_AUTH,
295036285Sbrian  "Van Jacobson header compression", "accept|deny|disable|enable",
295136285Sbrian  (const void *)NEG_VJCOMP},
295236285Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
295336285Sbrian  "Display this message", "accept|deny|disable|enable help|? [value]",
295436285Sbrian  NegotiateCommands},
295536285Sbrian  {NULL, NULL, NULL},
295636285Sbrian};
295736285Sbrian
295836285Sbrianstatic int
295936285SbrianNegotiateCommand(struct cmdargs const *arg)
296036285Sbrian{
296136285Sbrian  if (arg->argc > arg->argn) {
296236285Sbrian    char const *argv[3];
296336285Sbrian    unsigned keep, add;
296436285Sbrian    int n;
296536285Sbrian
296636285Sbrian    if ((argv[0] = ident_cmd(arg->argv[arg->argn-1], &keep, &add)) == NULL)
296736285Sbrian      return -1;
296836285Sbrian    argv[2] = NULL;
296936285Sbrian
297036285Sbrian    for (n = arg->argn; n < arg->argc; n++) {
297136285Sbrian      argv[1] = arg->argv[n];
297236285Sbrian      FindExec(arg->bundle, NegotiateCommands + (keep == NEG_HISMASK ?
297336285Sbrian               0 : OPT_MAX), 2, 1, argv, arg->prompt, arg->cx);
297436285Sbrian    }
297536285Sbrian  } else if (arg->prompt)
297636285Sbrian    prompt_Printf(arg->prompt, "Use `%s ?' to get a list.\n",
297736285Sbrian	    arg->argv[arg->argn-1]);
297836285Sbrian  else
297936285Sbrian    log_Printf(LogWARN, "%s command must have arguments\n",
298036285Sbrian              arg->argv[arg->argn] );
298136285Sbrian
298236285Sbrian  return 0;
298336285Sbrian}
298436285Sbrian
298536285Sbrianconst char *
298636285Sbriancommand_ShowNegval(unsigned val)
298736285Sbrian{
298836285Sbrian  switch (val&3) {
298936285Sbrian    case 1: return "disabled & accepted";
299036285Sbrian    case 2: return "enabled & denied";
299136285Sbrian    case 3: return "enabled & accepted";
299236285Sbrian  }
299336285Sbrian  return "disabled & denied";
299436285Sbrian}
299536934Sbrian
299636934Sbrianstatic int
299736934SbrianClearCommand(struct cmdargs const *arg)
299836934Sbrian{
299936934Sbrian  struct pppThroughput *t;
300036934Sbrian  struct datalink *cx;
300136934Sbrian  int i, clear_type;
300236934Sbrian
300336934Sbrian  if (arg->argc < arg->argn + 1)
300436934Sbrian    return -1;
300536934Sbrian
300646686Sbrian  if (strcasecmp(arg->argv[arg->argn], "physical") == 0) {
300736934Sbrian    cx = arg->cx;
300836934Sbrian    if (!cx)
300936934Sbrian      cx = bundle2datalink(arg->bundle, NULL);
301036934Sbrian    if (!cx) {
301146686Sbrian      log_Printf(LogWARN, "A link must be specified for ``clear physical''\n");
301236934Sbrian      return 1;
301336934Sbrian    }
301464652Sbrian    t = &cx->physical->link.stats.total;
301536934Sbrian  } else if (strcasecmp(arg->argv[arg->argn], "ipcp") == 0)
301636934Sbrian    t = &arg->bundle->ncp.ipcp.throughput;
301781634Sbrian#ifndef NOINET6
301881897Sbrian  else if (strcasecmp(arg->argv[arg->argn], "ipv6cp") == 0)
301981634Sbrian    t = &arg->bundle->ncp.ipv6cp.throughput;
302081634Sbrian#endif
302136934Sbrian  else
302236934Sbrian    return -1;
302336934Sbrian
302436934Sbrian  if (arg->argc > arg->argn + 1) {
302536934Sbrian    clear_type = 0;
302636934Sbrian    for (i = arg->argn + 1; i < arg->argc; i++)
302736934Sbrian      if (strcasecmp(arg->argv[i], "overall") == 0)
302836934Sbrian        clear_type |= THROUGHPUT_OVERALL;
302936934Sbrian      else if (strcasecmp(arg->argv[i], "current") == 0)
303036934Sbrian        clear_type |= THROUGHPUT_CURRENT;
303136934Sbrian      else if (strcasecmp(arg->argv[i], "peak") == 0)
303236934Sbrian        clear_type |= THROUGHPUT_PEAK;
303336934Sbrian      else
303436934Sbrian        return -1;
303598243Sbrian  } else
303636934Sbrian    clear_type = THROUGHPUT_ALL;
303736934Sbrian
303836934Sbrian  throughput_clear(t, clear_type, arg->prompt);
303936934Sbrian  return 0;
304036934Sbrian}
304140561Sbrian
304240561Sbrianstatic int
304340561SbrianRunListCommand(struct cmdargs const *arg)
304440561Sbrian{
304540561Sbrian  const char *cmd = arg->argc ? arg->argv[arg->argc - 1] : "???";
304640561Sbrian
304764801Sbrian#ifndef NONAT
304864801Sbrian  if (arg->cmd->args == NatCommands &&
304964801Sbrian      tolower(*arg->argv[arg->argn - 1]) == 'a') {
305064801Sbrian    if (arg->prompt)
305165550Sbrian      prompt_Printf(arg->prompt, "The alias command is deprecated\n");
305264801Sbrian    else
305365550Sbrian      log_Printf(LogWARN, "The alias command is deprecated\n");
305464801Sbrian  }
305564801Sbrian#endif
305664801Sbrian
305740561Sbrian  if (arg->argc > arg->argn)
305840561Sbrian    FindExec(arg->bundle, arg->cmd->args, arg->argc, arg->argn, arg->argv,
305940561Sbrian             arg->prompt, arg->cx);
306040561Sbrian  else if (arg->prompt)
306140561Sbrian    prompt_Printf(arg->prompt, "Use `%s help' to get a list or `%s help"
306240561Sbrian                  " <option>' for syntax help.\n", cmd, cmd);
306340561Sbrian  else
306440561Sbrian    log_Printf(LogWARN, "%s command must have arguments\n", cmd);
306540561Sbrian
306640561Sbrian  return 0;
306740561Sbrian}
306840561Sbrian
306940561Sbrianstatic int
307040561SbrianIfaceAddCommand(struct cmdargs const *arg)
307140561Sbrian{
307281634Sbrian  struct ncpaddr peer, addr;
307381634Sbrian  struct ncprange ifa;
307481634Sbrian  struct in_addr mask;
307581634Sbrian  int n, how;
307640561Sbrian
307740664Sbrian  if (arg->argc == arg->argn + 1) {
307881634Sbrian    if (!ncprange_aton(&ifa, NULL, arg->argv[arg->argn]))
307940561Sbrian      return -1;
308081634Sbrian    ncpaddr_init(&peer);
308140664Sbrian  } else {
308240664Sbrian    if (arg->argc == arg->argn + 2) {
308381634Sbrian      if (!ncprange_aton(&ifa, NULL, arg->argv[arg->argn]))
308440664Sbrian        return -1;
308540664Sbrian      n = 1;
308640664Sbrian    } else if (arg->argc == arg->argn + 3) {
308781634Sbrian      if (!ncpaddr_aton(&addr, NULL, arg->argv[arg->argn]))
308840664Sbrian        return -1;
308981634Sbrian      if (ncpaddr_family(&addr) != AF_INET)
309040664Sbrian        return -1;
309181634Sbrian      ncprange_sethost(&ifa, &addr);
309281634Sbrian      if (!ncpaddr_aton(&addr, NULL, arg->argv[arg->argn + 1]))
309381634Sbrian        return -1;
309481634Sbrian      if (!ncpaddr_getip4(&addr, &mask))
309581634Sbrian        return -1;
309681634Sbrian      if (!ncprange_setip4mask(&ifa, mask))
309781634Sbrian        return -1;
309840664Sbrian      n = 2;
309940664Sbrian    } else
310040561Sbrian      return -1;
310140561Sbrian
310281634Sbrian    if (!ncpaddr_aton(&peer, NULL, arg->argv[arg->argn + n]))
310340664Sbrian      return -1;
310481634Sbrian
310581634Sbrian    if (ncprange_family(&ifa) != ncpaddr_family(&peer)) {
310681634Sbrian      log_Printf(LogWARN, "IfaceAddCommand: src and dst address families"
310781634Sbrian                 " differ\n");
310881634Sbrian      return -1;
310981634Sbrian    }
311040664Sbrian  }
311140561Sbrian
311240561Sbrian  how = IFACE_ADD_LAST;
311340561Sbrian  if (arg->cmd->args)
311440561Sbrian    how |= IFACE_FORCE_ADD;
311540561Sbrian
311681634Sbrian  return !iface_Add(arg->bundle->iface, &arg->bundle->ncp, &ifa, &peer, how);
311740561Sbrian}
311840561Sbrian
311940561Sbrianstatic int
312040561SbrianIfaceDeleteCommand(struct cmdargs const *arg)
312140561Sbrian{
312281634Sbrian  struct ncpaddr ifa;
312381634Sbrian  struct in_addr ifa4;
312440561Sbrian  int ok;
312540561Sbrian
312640561Sbrian  if (arg->argc != arg->argn + 1)
312740561Sbrian    return -1;
312840561Sbrian
312981634Sbrian  if (!ncpaddr_aton(&ifa, NULL, arg->argv[arg->argn]))
313040561Sbrian    return -1;
313140561Sbrian
313240561Sbrian  if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED &&
313381634Sbrian      ncpaddr_getip4(&ifa, &ifa4) &&
313481634Sbrian      arg->bundle->ncp.ipcp.my_ip.s_addr == ifa4.s_addr) {
313540561Sbrian    log_Printf(LogWARN, "%s: Cannot remove active interface address\n",
313681634Sbrian               ncpaddr_ntoa(&ifa));
313740561Sbrian    return 1;
313840561Sbrian  }
313940561Sbrian
314081634Sbrian  ok = iface_Delete(arg->bundle->iface, &arg->bundle->ncp, &ifa);
314140561Sbrian  if (!ok) {
314240561Sbrian    if (arg->cmd->args)
314340561Sbrian      ok = 1;
314440561Sbrian    else if (arg->prompt)
314581634Sbrian      prompt_Printf(arg->prompt, "%s: No such interface address\n",
314681634Sbrian                    ncpaddr_ntoa(&ifa));
314740561Sbrian    else
314881634Sbrian      log_Printf(LogWARN, "%s: No such interface address\n",
314981634Sbrian                 ncpaddr_ntoa(&ifa));
315040561Sbrian  }
315140561Sbrian
315240561Sbrian  return !ok;
315340561Sbrian}
315440561Sbrian
315540561Sbrianstatic int
315640561SbrianIfaceClearCommand(struct cmdargs const *arg)
315740561Sbrian{
315881634Sbrian  int family, how;
315940561Sbrian
316081634Sbrian  family = 0;
316181634Sbrian  if (arg->argc == arg->argn + 1) {
316281634Sbrian    if (strcasecmp(arg->argv[arg->argn], "inet") == 0)
316381634Sbrian      family = AF_INET;
316481634Sbrian#ifndef NOINET6
316581897Sbrian    else if (strcasecmp(arg->argv[arg->argn], "inet6") == 0)
316681634Sbrian      family = AF_INET6;
316781634Sbrian#endif
316881634Sbrian    else
316981634Sbrian      return -1;
317081634Sbrian  } else if (arg->argc != arg->argn)
317140561Sbrian    return -1;
317240561Sbrian
317340941Sbrian  how = arg->bundle->ncp.ipcp.fsm.state == ST_OPENED ||
317440941Sbrian        arg->bundle->phys_type.all & PHYS_AUTO ?
317540561Sbrian        IFACE_CLEAR_ALIASES : IFACE_CLEAR_ALL;
317681634Sbrian  iface_Clear(arg->bundle->iface, &arg->bundle->ncp, family, how);
317740561Sbrian
317840561Sbrian  return 0;
317940561Sbrian}
318040679Sbrian
318140679Sbrianstatic int
318240679SbrianSetProcTitle(struct cmdargs const *arg)
318340679Sbrian{
318440679Sbrian  static char title[LINE_LEN];
318586028Sbrian  char *argv[MAXARGS];
318686028Sbrian  int argc = arg->argc - arg->argn;
318740679Sbrian
318840679Sbrian  if (arg->argc == arg->argn) {
318964698Sbrian    SetTitle(NULL);
319040679Sbrian    return 0;
319140679Sbrian  }
319240679Sbrian
319340679Sbrian  if (argc >= sizeof argv / sizeof argv[0]) {
319440679Sbrian    argc = sizeof argv / sizeof argv[0] - 1;
319540679Sbrian    log_Printf(LogWARN, "Truncating proc title to %d args\n", argc);
319640679Sbrian  }
319747849Sbrian  command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 1, getpid());
319885991Sbrian  Concatinate(title, sizeof title, argc, (const char *const *)argv);
319964698Sbrian  SetTitle(title);
320085991Sbrian  command_Free(argc, argv);
320140679Sbrian
320240679Sbrian  return 0;
320340679Sbrian}
3204