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$
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
145132273Sbrian#define	VAR_RAD_ALIVE	38
146132818Sglebius#define	VAR_PPPOE	39
147169986Snovel#define	VAR_PORT_ID	40
1486059Samurai
14936285Sbrian/* ``accept|deny|disable|enable'' masks */
15036285Sbrian#define NEG_HISMASK (1)
15136285Sbrian#define NEG_MYMASK (2)
15236285Sbrian
15336285Sbrian/* ``accept|deny|disable|enable'' values */
15436285Sbrian#define NEG_ACFCOMP	40
15544106Sbrian#define NEG_CHAP05	41
15644106Sbrian#define NEG_CHAP80	42
15744106Sbrian#define NEG_CHAP80LM	43
15844106Sbrian#define NEG_DEFLATE	44
15947858Sbrian#define NEG_DNS		45
160138799Sbrian#define NEG_ECHO	46
161138799Sbrian#define NEG_ENDDISC	47
162138799Sbrian#define NEG_LQR		48
163138799Sbrian#define NEG_PAP		49
164138799Sbrian#define NEG_PPPDDEFLATE	50
165138799Sbrian#define NEG_PRED1	51
166138799Sbrian#define NEG_PROTOCOMP	52
167138799Sbrian#define NEG_SHORTSEQ	53
168138799Sbrian#define NEG_VJCOMP	54
169138799Sbrian#define NEG_MPPE	55
170138799Sbrian#define NEG_CHAP81	56
17136285Sbrian
172138799Sbrianconst char Version[] = "3.4.2";
17336285Sbrian
17436285Sbrianstatic int ShowCommand(struct cmdargs const *);
17536285Sbrianstatic int TerminalCommand(struct cmdargs const *);
17636285Sbrianstatic int QuitCommand(struct cmdargs const *);
17736285Sbrianstatic int OpenCommand(struct cmdargs const *);
17836285Sbrianstatic int CloseCommand(struct cmdargs const *);
17936285Sbrianstatic int DownCommand(struct cmdargs const *);
18036285Sbrianstatic int SetCommand(struct cmdargs const *);
18136285Sbrianstatic int LinkCommand(struct cmdargs const *);
18236285Sbrianstatic int AddCommand(struct cmdargs const *);
18336285Sbrianstatic int DeleteCommand(struct cmdargs const *);
18436285Sbrianstatic int NegotiateCommand(struct cmdargs const *);
18536934Sbrianstatic int ClearCommand(struct cmdargs const *);
18640561Sbrianstatic int RunListCommand(struct cmdargs const *);
187218397Sbrianstatic int IfaceNameCommand(struct cmdargs const *arg);
18840561Sbrianstatic int IfaceAddCommand(struct cmdargs const *);
18940561Sbrianstatic int IfaceDeleteCommand(struct cmdargs const *);
19040561Sbrianstatic int IfaceClearCommand(struct cmdargs const *);
19140679Sbrianstatic int SetProcTitle(struct cmdargs const *);
19250059Sbrian#ifndef NONAT
19358867Sbrianstatic int NatEnable(struct cmdargs const *);
19458867Sbrianstatic int NatOption(struct cmdargs const *);
19531343Sbrian#endif
1966059Samurai
197177100Spisoextern struct libalias *la;
198177100Spiso
19936285Sbrianstatic const char *
20036285Sbrianshowcx(struct cmdtab const *cmd)
20136285Sbrian{
20236285Sbrian  if (cmd->lauth & LOCAL_CX)
20336285Sbrian    return "(c)";
20436285Sbrian  else if (cmd->lauth & LOCAL_CX_OPT)
20536285Sbrian    return "(o)";
20636285Sbrian
20736285Sbrian  return "";
20836285Sbrian}
20936285Sbrian
2106059Samuraistatic int
21131343SbrianHelpCommand(struct cmdargs const *arg)
2126059Samurai{
21328679Sbrian  struct cmdtab const *cmd;
21436285Sbrian  int n, cmax, dmax, cols, cxlen;
21536285Sbrian  const char *cx;
2166059Samurai
21736285Sbrian  if (!arg->prompt) {
21836285Sbrian    log_Printf(LogWARN, "help: Cannot help without a prompt\n");
21926516Sbrian    return 0;
22036285Sbrian  }
22126516Sbrian
22236285Sbrian  if (arg->argc > arg->argn) {
22336285Sbrian    for (cmd = arg->cmdtab; cmd->name || cmd->alias; cmd++)
22436285Sbrian      if ((cmd->lauth & arg->prompt->auth) &&
22536285Sbrian          ((cmd->name && !strcasecmp(cmd->name, arg->argv[arg->argn])) ||
22636285Sbrian           (cmd->alias && !strcasecmp(cmd->alias, arg->argv[arg->argn])))) {
22736285Sbrian	prompt_Printf(arg->prompt, "%s %s\n", cmd->syntax, showcx(cmd));
22828679Sbrian	return 0;
2296059Samurai      }
23026516Sbrian    return -1;
2316059Samurai  }
23236285Sbrian
23331372Sbrian  cmax = dmax = 0;
23436285Sbrian  for (cmd = arg->cmdtab; cmd->func; cmd++)
23536285Sbrian    if (cmd->name && (cmd->lauth & arg->prompt->auth)) {
23636285Sbrian      if ((n = strlen(cmd->name) + strlen(showcx(cmd))) > cmax)
23731372Sbrian        cmax = n;
23831372Sbrian      if ((n = strlen(cmd->helpmes)) > dmax)
23931372Sbrian        dmax = n;
24031372Sbrian    }
24131372Sbrian
24231372Sbrian  cols = 80 / (dmax + cmax + 3);
2436059Samurai  n = 0;
24436285Sbrian  prompt_Printf(arg->prompt, "(o) = Optional context,"
24536285Sbrian                " (c) = Context required\n");
24636285Sbrian  for (cmd = arg->cmdtab; cmd->func; cmd++)
24736285Sbrian    if (cmd->name && (cmd->lauth & arg->prompt->auth)) {
24836285Sbrian      cx = showcx(cmd);
24936285Sbrian      cxlen = cmax - strlen(cmd->name);
25040482Sbrian      if (n % cols != 0)
25140482Sbrian        prompt_Printf(arg->prompt, " ");
25240482Sbrian      prompt_Printf(arg->prompt, "%s%-*.*s: %-*.*s",
25336285Sbrian              cmd->name, cxlen, cxlen, cx, dmax, dmax, cmd->helpmes);
25431372Sbrian      if (++n % cols == 0)
25536285Sbrian        prompt_Printf(arg->prompt, "\n");
2566059Samurai    }
25731372Sbrian  if (n % cols != 0)
25836285Sbrian    prompt_Printf(arg->prompt, "\n");
25926516Sbrian
26026516Sbrian  return 0;
2616059Samurai}
2626059Samurai
26336285Sbrianstatic int
26463484SbrianIdentCommand(struct cmdargs const *arg)
26563484Sbrian{
26685991Sbrian  Concatinate(arg->cx->physical->link.lcp.cfg.ident,
26785991Sbrian              sizeof arg->cx->physical->link.lcp.cfg.ident,
26885991Sbrian              arg->argc - arg->argn, arg->argv + arg->argn);
26963484Sbrian  return 0;
27063484Sbrian}
27163484Sbrian
27263484Sbrianstatic int
27363484SbrianSendIdentification(struct cmdargs const *arg)
27463484Sbrian{
27563484Sbrian  if (arg->cx->state < DATALINK_LCP) {
27663484Sbrian    log_Printf(LogWARN, "sendident: link has not reached LCP\n");
27763484Sbrian    return 2;
27863484Sbrian  }
27963484Sbrian  return lcp_SendIdentification(&arg->cx->physical->link.lcp) ? 0 : 1;
28063484Sbrian}
28163484Sbrian
28263484Sbrianstatic int
28336285SbrianCloneCommand(struct cmdargs const *arg)
2846059Samurai{
28536285Sbrian  char namelist[LINE_LEN];
28636285Sbrian  char *name;
28736285Sbrian  int f;
2886059Samurai
28936285Sbrian  if (arg->argc == arg->argn)
29036285Sbrian    return -1;
29136285Sbrian
29236285Sbrian  namelist[sizeof namelist - 1] = '\0';
29336285Sbrian  for (f = arg->argn; f < arg->argc; f++) {
29436285Sbrian    strncpy(namelist, arg->argv[f], sizeof namelist - 1);
29536285Sbrian    for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
29636285Sbrian      bundle_DatalinkClone(arg->bundle, arg->cx, name);
2976059Samurai  }
29836285Sbrian
29936285Sbrian  return 0;
3006059Samurai}
3016059Samurai
3026059Samuraistatic int
30336285SbrianRemoveCommand(struct cmdargs const *arg)
3046059Samurai{
30536285Sbrian  if (arg->argc != arg->argn)
30636285Sbrian    return -1;
30711336Samurai
30836285Sbrian  if (arg->cx->state != DATALINK_CLOSED) {
30936285Sbrian    log_Printf(LogWARN, "remove: Cannot delete links that aren't closed\n");
31036285Sbrian    return 2;
3116059Samurai  }
31226516Sbrian
31336285Sbrian  bundle_DatalinkRemove(arg->bundle, arg->cx);
31436285Sbrian  return 0;
31536285Sbrian}
31632711Sbrian
31736285Sbrianstatic int
31836285SbrianRenameCommand(struct cmdargs const *arg)
31936285Sbrian{
32036285Sbrian  if (arg->argc != arg->argn + 1)
32136285Sbrian    return -1;
32231121Sbrian
32336285Sbrian  if (bundle_RenameDatalink(arg->bundle, arg->cx, arg->argv[arg->argn]))
32436285Sbrian    return 0;
32536285Sbrian
32698243Sbrian  log_Printf(LogWARN, "%s -> %s: target name already exists\n",
32736285Sbrian             arg->cx->name, arg->argv[arg->argn]);
32836285Sbrian  return 1;
32936285Sbrian}
33036285Sbrian
33185991Sbrianstatic int
33236285SbrianLoadCommand(struct cmdargs const *arg)
33336285Sbrian{
33440797Sbrian  const char *err;
33540797Sbrian  int n, mode;
33636285Sbrian
33740797Sbrian  mode = arg->bundle->phys_type.all;
33836285Sbrian
33940797Sbrian  if (arg->argn < arg->argc) {
34040797Sbrian    for (n = arg->argn; n < arg->argc; n++)
34140797Sbrian      if ((err = system_IsValid(arg->argv[n], arg->prompt, mode)) != NULL) {
34240797Sbrian        log_Printf(LogWARN, "%s: %s\n", arg->argv[n], err);
34340797Sbrian        return 1;
34440797Sbrian      }
34540797Sbrian
34640797Sbrian    for (n = arg->argn; n < arg->argc; n++) {
34740797Sbrian      bundle_SetLabel(arg->bundle, arg->argv[arg->argc - 1]);
34840797Sbrian      system_Select(arg->bundle, arg->argv[n], CONFFILE, arg->prompt, arg->cx);
34940797Sbrian    }
35040797Sbrian    bundle_SetLabel(arg->bundle, arg->argv[arg->argc - 1]);
35140797Sbrian  } else if ((err = system_IsValid("default", arg->prompt, mode)) != NULL) {
35240797Sbrian    log_Printf(LogWARN, "default: %s\n", err);
35336285Sbrian    return 1;
35436285Sbrian  } else {
35540797Sbrian    bundle_SetLabel(arg->bundle, "default");
35640797Sbrian    system_Select(arg->bundle, "default", CONFFILE, arg->prompt, arg->cx);
35740797Sbrian    bundle_SetLabel(arg->bundle, "default");
35836285Sbrian  }
35940797Sbrian
36026516Sbrian  return 0;
3616059Samurai}
3626059Samurai
36385991Sbrianstatic int
36485991SbrianLogCommand(struct cmdargs const *arg)
36585991Sbrian{
36685991Sbrian  char buf[LINE_LEN];
36785991Sbrian
36885991Sbrian  if (arg->argn < arg->argc) {
36985991Sbrian    char *argv[MAXARGS];
37085991Sbrian    int argc = arg->argc - arg->argn;
37185991Sbrian
372134789Sbrian    if (argc >= (int)(sizeof argv / sizeof argv[0])) {
37385991Sbrian      argc = sizeof argv / sizeof argv[0] - 1;
37485991Sbrian      log_Printf(LogWARN, "Truncating log command to %d args\n", argc);
37585991Sbrian    }
37686760Sbrian    command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 1, getpid());
37785991Sbrian    Concatinate(buf, sizeof buf, argc, (const char *const *)argv);
37885991Sbrian    log_Printf(LogLOG, "%s\n", buf);
37985991Sbrian    command_Free(argc, argv);
38085991Sbrian    return 0;
38185991Sbrian  }
38285991Sbrian
38385991Sbrian  return -1;
38485991Sbrian}
38585991Sbrian
38685991Sbrianstatic int
387134789SbrianSaveCommand(struct cmdargs const *arg __unused)
38836285Sbrian{
38985991Sbrian  log_Printf(LogWARN, "save command is not yet implemented.\n");
39036285Sbrian  return 1;
39136285Sbrian}
39236285Sbrian
39310528Samuraistatic int
39436285SbrianDialCommand(struct cmdargs const *arg)
39528536Sbrian{
39636285Sbrian  int res;
39736285Sbrian
39836465Sbrian  if ((arg->cx && !(arg->cx->physical->type & (PHYS_INTERACTIVE|PHYS_AUTO)))
39936465Sbrian      || (!arg->cx &&
40036928Sbrian          (arg->bundle->phys_type.all & ~(PHYS_INTERACTIVE|PHYS_AUTO)))) {
40136285Sbrian    log_Printf(LogWARN, "Manual dial is only available for auto and"
40236285Sbrian              " interactive links\n");
40336285Sbrian    return 1;
40434536Sbrian  }
40536285Sbrian
40636285Sbrian  if (arg->argc > arg->argn && (res = LoadCommand(arg)) != 0)
40736285Sbrian    return res;
40836285Sbrian
40937993Sbrian  bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1);
41036285Sbrian
41136285Sbrian  return 0;
41228536Sbrian}
41328536Sbrian
41438628Sbrian#define isinword(ch) (isalnum(ch) || (ch) == '_')
41538628Sbrian
41638628Sbrianstatic char *
41738628Sbrianstrstrword(char *big, const char *little)
41838628Sbrian{
419249582Sgabor  /* Get the first occurrence of the word ``little'' in ``big'' */
42038628Sbrian  char *pos;
42138628Sbrian  int len;
42238628Sbrian
42338628Sbrian  pos = big;
42438628Sbrian  len = strlen(little);
42538628Sbrian
42638628Sbrian  while ((pos = strstr(pos, little)) != NULL)
42747865Sbrian    if ((pos != big && isinword(pos[-1])) || isinword(pos[len]))
42847865Sbrian      pos++;
42947865Sbrian    else if (pos != big && pos[-1] == '\\')
43047865Sbrian      memmove(pos - 1, pos, strlen(pos) + 1);
43147865Sbrian    else
43238628Sbrian      break;
43338628Sbrian
43438628Sbrian  return pos;
43538628Sbrian}
43638628Sbrian
43738628Sbrianstatic char *
43838628Sbriansubst(char *tgt, const char *oldstr, const char *newstr)
43938628Sbrian{
44038628Sbrian  /* tgt is a malloc()d area... realloc() as necessary */
44138628Sbrian  char *word, *ntgt;
44238628Sbrian  int ltgt, loldstr, lnewstr, pos;
44338628Sbrian
44438628Sbrian  if ((word = strstrword(tgt, oldstr)) == NULL)
44538628Sbrian    return tgt;
44638628Sbrian
44738628Sbrian  ltgt = strlen(tgt) + 1;
44838628Sbrian  loldstr = strlen(oldstr);
44938628Sbrian  lnewstr = strlen(newstr);
45038628Sbrian  do {
45138628Sbrian    pos = word - tgt;
45238628Sbrian    if (loldstr > lnewstr)
45338628Sbrian      bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr);
45438628Sbrian    if (loldstr != lnewstr) {
45538628Sbrian      ntgt = realloc(tgt, ltgt += lnewstr - loldstr);
45638628Sbrian      if (ntgt == NULL)
45738628Sbrian        break;			/* Oh wonderful ! */
45838628Sbrian      word = ntgt + pos;
45938628Sbrian      tgt = ntgt;
46038628Sbrian    }
46138628Sbrian    if (lnewstr > loldstr)
462141504Sbrian      bcopy(word + loldstr, word + lnewstr, ltgt - pos - lnewstr);
46338628Sbrian    bcopy(newstr, word, lnewstr);
46438628Sbrian  } while ((word = strstrword(word, oldstr)));
46538628Sbrian
46638628Sbrian  return tgt;
46738628Sbrian}
46838628Sbrian
46994934Sbrianstatic char *
47094934Sbriansubstip(char *tgt, const char *oldstr, struct in_addr ip)
47194934Sbrian{
47294934Sbrian  return subst(tgt, oldstr, inet_ntoa(ip));
47394934Sbrian}
47494934Sbrian
47594934Sbrianstatic char *
47697360Sbriansubstlong(char *tgt, const char *oldstr, long l)
47794934Sbrian{
47897360Sbrian  char buf[23];
47994934Sbrian
48097360Sbrian  snprintf(buf, sizeof buf, "%ld", l);
48194934Sbrian
48294934Sbrian  return subst(tgt, oldstr, buf);
48394934Sbrian}
48494934Sbrian
48594934Sbrianstatic char *
48694934Sbriansubstull(char *tgt, const char *oldstr, unsigned long long ull)
48794934Sbrian{
48894934Sbrian  char buf[21];
48994934Sbrian
49094934Sbrian  snprintf(buf, sizeof buf, "%llu", ull);
49194934Sbrian
49294934Sbrian  return subst(tgt, oldstr, buf);
49394934Sbrian}
49494934Sbrian
49594934Sbrian
49694934Sbrian#ifndef NOINET6
49794934Sbrianstatic char *
49894934Sbriansubstipv6(char *tgt, const char *oldstr, const struct ncpaddr *ip)
49994934Sbrian{
50094934Sbrian    return subst(tgt, oldstr, ncpaddr_ntoa(ip));
50194934Sbrian}
502116622Sume
503116622Sume#ifndef NORADIUS
504116622Sumestatic char *
505116622Sumesubstipv6prefix(char *tgt, const char *oldstr, const uint8_t *ipv6prefix)
506116622Sume{
507116622Sume  uint8_t ipv6addr[INET6_ADDRSTRLEN];
508116622Sume  uint8_t prefix[INET6_ADDRSTRLEN + sizeof("/128") - 1];
509116622Sume
510116622Sume  if (ipv6prefix) {
511116622Sume    inet_ntop(AF_INET6, &ipv6prefix[2], ipv6addr, sizeof(ipv6addr));
512116622Sume    snprintf(prefix, sizeof(prefix), "%s/%d", ipv6addr, ipv6prefix[1]);
513116622Sume  } else
514116622Sume    prefix[0] = '\0';
515116622Sume  return subst(tgt, oldstr, prefix);
516116622Sume}
51794934Sbrian#endif
518116622Sume#endif
51994934Sbrian
52043888Sbrianvoid
52143888Sbriancommand_Expand(char **nargv, int argc, char const *const *oargv,
52247849Sbrian               struct bundle *bundle, int inc0, pid_t pid)
52338628Sbrian{
52485991Sbrian  int arg, secs;
52594934Sbrian  char uptime[20];
52694934Sbrian  unsigned long long oin, oout, pin, pout;
52738628Sbrian
52841755Sbrian  if (inc0)
52941755Sbrian    arg = 0;		/* Start at arg 0 */
53041755Sbrian  else {
53141755Sbrian    nargv[0] = strdup(oargv[0]);
53241755Sbrian    arg = 1;
53341755Sbrian  }
53494934Sbrian
53594934Sbrian  secs = bundle_Uptime(bundle);
53694934Sbrian  snprintf(uptime, sizeof uptime, "%d:%02d:%02d",
53794934Sbrian           secs / 3600, (secs / 60) % 60, secs % 60);
53894934Sbrian  oin = bundle->ncp.ipcp.throughput.OctetsIn;
53994934Sbrian  oout = bundle->ncp.ipcp.throughput.OctetsOut;
54094934Sbrian  pin = bundle->ncp.ipcp.throughput.PacketsIn;
54194934Sbrian  pout = bundle->ncp.ipcp.throughput.PacketsOut;
54294934Sbrian#ifndef NOINET6
54394934Sbrian  oin += bundle->ncp.ipv6cp.throughput.OctetsIn;
54494934Sbrian  oout += bundle->ncp.ipv6cp.throughput.OctetsOut;
54594934Sbrian  pin += bundle->ncp.ipv6cp.throughput.PacketsIn;
54694934Sbrian  pout += bundle->ncp.ipv6cp.throughput.PacketsOut;
54794934Sbrian#endif
54894934Sbrian
54941755Sbrian  for (; arg < argc; arg++) {
55038629Sbrian    nargv[arg] = strdup(oargv[arg]);
55194934Sbrian    nargv[arg] = subst(nargv[arg], "AUTHNAME", bundle->cfg.auth.name);
55294934Sbrian    nargv[arg] = substip(nargv[arg], "DNS0", bundle->ncp.ipcp.ns.dns[0]);
55394934Sbrian    nargv[arg] = substip(nargv[arg], "DNS1", bundle->ncp.ipcp.ns.dns[1]);
55498243Sbrian    nargv[arg] = subst(nargv[arg], "ENDDISC",
55594934Sbrian                       mp_Enddisc(bundle->ncp.mp.cfg.enddisc.class,
55694934Sbrian                                  bundle->ncp.mp.cfg.enddisc.address,
55794934Sbrian                                  bundle->ncp.mp.cfg.enddisc.len));
55894934Sbrian    nargv[arg] = substip(nargv[arg], "HISADDR", bundle->ncp.ipcp.peer_ip);
55981634Sbrian#ifndef NOINET6
56094934Sbrian    nargv[arg] = substipv6(nargv[arg], "HISADDR6", &bundle->ncp.ipv6cp.hisaddr);
56181634Sbrian#endif
56240561Sbrian    nargv[arg] = subst(nargv[arg], "INTERFACE", bundle->iface->name);
56394934Sbrian    nargv[arg] = substull(nargv[arg], "IPOCTETSIN",
56494934Sbrian                          bundle->ncp.ipcp.throughput.OctetsIn);
56598243Sbrian    nargv[arg] = substull(nargv[arg], "IPOCTETSOUT",
56694934Sbrian                          bundle->ncp.ipcp.throughput.OctetsOut);
56798243Sbrian    nargv[arg] = substull(nargv[arg], "IPPACKETSIN",
56894934Sbrian                          bundle->ncp.ipcp.throughput.PacketsIn);
56998243Sbrian    nargv[arg] = substull(nargv[arg], "IPPACKETSOUT",
57094934Sbrian                          bundle->ncp.ipcp.throughput.PacketsOut);
57181634Sbrian#ifndef NOINET6
57298243Sbrian    nargv[arg] = substull(nargv[arg], "IPV6OCTETSIN",
57394934Sbrian                          bundle->ncp.ipv6cp.throughput.OctetsIn);
57498243Sbrian    nargv[arg] = substull(nargv[arg], "IPV6OCTETSOUT",
57594934Sbrian                          bundle->ncp.ipv6cp.throughput.OctetsOut);
57698243Sbrian    nargv[arg] = substull(nargv[arg], "IPV6PACKETSIN",
57794934Sbrian                          bundle->ncp.ipv6cp.throughput.PacketsIn);
57898243Sbrian    nargv[arg] = substull(nargv[arg], "IPV6PACKETSOUT",
57994934Sbrian                          bundle->ncp.ipv6cp.throughput.PacketsOut);
58081634Sbrian#endif
58194934Sbrian    nargv[arg] = subst(nargv[arg], "LABEL", bundle_GetLabel(bundle));
58294934Sbrian    nargv[arg] = substip(nargv[arg], "MYADDR", bundle->ncp.ipcp.my_ip);
58394934Sbrian#ifndef NOINET6
58494934Sbrian    nargv[arg] = substipv6(nargv[arg], "MYADDR6", &bundle->ncp.ipv6cp.myaddr);
585116622Sume#ifndef NORADIUS
586116622Sume    nargv[arg] = substipv6prefix(nargv[arg], "IPV6PREFIX",
587116622Sume				 bundle->radius.ipv6prefix);
58894934Sbrian#endif
589116622Sume#endif
59094934Sbrian    nargv[arg] = substull(nargv[arg], "OCTETSIN", oin);
59194934Sbrian    nargv[arg] = substull(nargv[arg], "OCTETSOUT", oout);
59294934Sbrian    nargv[arg] = substull(nargv[arg], "PACKETSIN", pin);
59394934Sbrian    nargv[arg] = substull(nargv[arg], "PACKETSOUT", pout);
59438629Sbrian    nargv[arg] = subst(nargv[arg], "PEER_ENDDISC",
59538629Sbrian                       mp_Enddisc(bundle->ncp.mp.peer.enddisc.class,
59638629Sbrian                                  bundle->ncp.mp.peer.enddisc.address,
59738629Sbrian                                  bundle->ncp.mp.peer.enddisc.len));
59897360Sbrian    nargv[arg] = substlong(nargv[arg], "PROCESSID", pid);
59994934Sbrian    if (server.cfg.port)
60097360Sbrian      nargv[arg] = substlong(nargv[arg], "SOCKNAME", server.cfg.port);
60194934Sbrian    else
60294934Sbrian      nargv[arg] = subst(nargv[arg], "SOCKNAME", server.cfg.sockname);
60394934Sbrian    nargv[arg] = subst(nargv[arg], "UPTIME", uptime);
60494934Sbrian    nargv[arg] = subst(nargv[arg], "USER", bundle->ncp.mp.peer.authname);
60563484Sbrian    nargv[arg] = subst(nargv[arg], "VERSION", Version);
60638628Sbrian  }
60738628Sbrian  nargv[arg] = NULL;
60838628Sbrian}
60938628Sbrian
61085991Sbrianvoid
61185991Sbriancommand_Free(int argc, char **argv)
61285991Sbrian{
61385991Sbrian  while (argc) {
61485991Sbrian    free(*argv);
61585991Sbrian    argc--;
61685991Sbrian    argv++;
61785991Sbrian  }
61885991Sbrian}
61985991Sbrian
62028536Sbrianstatic int
62131343SbrianShellCommand(struct cmdargs const *arg, int bg)
62210528Samurai{
62310528Samurai  const char *shell;
62447849Sbrian  pid_t shpid, pid;
62520813Sjkh
62618856Ssos#ifdef SHELL_ONLY_INTERACTIVELY
62726911Sbrian  /* we're only allowed to shell when we run ppp interactively */
62836285Sbrian  if (arg->prompt && arg->prompt->owner) {
62936285Sbrian    log_Printf(LogWARN, "Can't start a shell from a network connection\n");
63026516Sbrian    return 1;
63110528Samurai  }
63226911Sbrian#endif
63328679Sbrian
63436285Sbrian  if (arg->argc == arg->argn) {
63536285Sbrian    if (!arg->prompt) {
63636285Sbrian      log_Printf(LogWARN, "Can't start an interactive shell from"
63736285Sbrian                " a config file\n");
63828381Sbrian      return 1;
63936285Sbrian    } else if (arg->prompt->owner) {
64036285Sbrian      log_Printf(LogWARN, "Can't start an interactive shell from"
64136285Sbrian                " a socket connection\n");
64236285Sbrian      return 1;
64328381Sbrian    } else if (bg) {
64436285Sbrian      log_Printf(LogWARN, "Can only start an interactive shell in"
64528679Sbrian		" the foreground mode\n");
64628381Sbrian      return 1;
64728381Sbrian    }
64834536Sbrian  }
64934536Sbrian
65047849Sbrian  pid = getpid();
65128679Sbrian  if ((shpid = fork()) == 0) {
65236285Sbrian    int i, fd;
65318531Sbde
65436285Sbrian    if ((shell = getenv("SHELL")) == 0)
65536285Sbrian      shell = _PATH_BSHELL;
65632017Sbrian
65736285Sbrian    timer_TermService();
65836285Sbrian
65936285Sbrian    if (arg->prompt)
66036285Sbrian      fd = arg->prompt->fd_out;
66136285Sbrian    else if ((fd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
66236285Sbrian      log_Printf(LogALERT, "Failed to open %s: %s\n",
66336285Sbrian                _PATH_DEVNULL, strerror(errno));
66428679Sbrian      exit(1);
66528679Sbrian    }
66649976Sbrian    dup2(fd, STDIN_FILENO);
66749976Sbrian    dup2(fd, STDOUT_FILENO);
66849976Sbrian    dup2(fd, STDERR_FILENO);
66949976Sbrian    for (i = getdtablesize(); i > STDERR_FILENO; i--)
67049976Sbrian      fcntl(i, F_SETFD, 1);
67126516Sbrian
67264802Sbrian#ifndef NOSUID
67355252Sbrian    setuid(ID0realuid());
67464802Sbrian#endif
67536285Sbrian    if (arg->argc > arg->argn) {
67628679Sbrian      /* substitute pseudo args */
67738628Sbrian      char *argv[MAXARGS];
67838628Sbrian      int argc = arg->argc - arg->argn;
67938628Sbrian
680134789Sbrian      if (argc >= (int)(sizeof argv / sizeof argv[0])) {
68138628Sbrian        argc = sizeof argv / sizeof argv[0] - 1;
68238628Sbrian        log_Printf(LogWARN, "Truncating shell command to %d args\n", argc);
68331343Sbrian      }
68447849Sbrian      command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 0, pid);
68528679Sbrian      if (bg) {
68628679Sbrian	pid_t p;
68710528Samurai
68828679Sbrian	p = getpid();
68928679Sbrian	if (daemon(1, 1) == -1) {
69097360Sbrian	  log_Printf(LogERROR, "%ld: daemon: %s\n", (long)p, strerror(errno));
69128679Sbrian	  exit(1);
69228679Sbrian	}
69336285Sbrian      } else if (arg->prompt)
69436285Sbrian        printf("ppp: Pausing until %s finishes\n", arg->argv[arg->argn]);
69531343Sbrian      execvp(argv[0], argv);
69630316Sbrian    } else {
69736285Sbrian      if (arg->prompt)
69832017Sbrian        printf("ppp: Pausing until %s finishes\n", shell);
69936285Sbrian      prompt_TtyOldMode(arg->prompt);
70079450Sbrian      execl(shell, shell, (char *)NULL);
70130316Sbrian    }
70220813Sjkh
70340665Sbrian    log_Printf(LogWARN, "exec() of %s failed: %s\n",
70440665Sbrian              arg->argc > arg->argn ? arg->argv[arg->argn] : shell,
70540665Sbrian              strerror(errno));
70649976Sbrian    _exit(255);
70710528Samurai  }
70836285Sbrian
70997360Sbrian  if (shpid == (pid_t)-1)
71036285Sbrian    log_Printf(LogERROR, "Fork failed: %s\n", strerror(errno));
71136285Sbrian  else {
71210528Samurai    int status;
71331343Sbrian    waitpid(shpid, &status, 0);
71410528Samurai  }
71520813Sjkh
71636285Sbrian  if (arg->prompt && !arg->prompt->owner)
71736285Sbrian    prompt_TtyCommandMode(arg->prompt);
71820813Sjkh
71936285Sbrian  return 0;
72010528Samurai}
72110528Samurai
72231343Sbrianstatic int
72331343SbrianBgShellCommand(struct cmdargs const *arg)
72431343Sbrian{
72536285Sbrian  if (arg->argc == arg->argn)
72631343Sbrian    return -1;
72731343Sbrian  return ShellCommand(arg, 1);
72831343Sbrian}
72931343Sbrian
73031343Sbrianstatic int
73131343SbrianFgShellCommand(struct cmdargs const *arg)
73231343Sbrian{
73331343Sbrian  return ShellCommand(arg, 0);
73431343Sbrian}
73531343Sbrian
73658044Sbrianstatic int
73758044SbrianResolvCommand(struct cmdargs const *arg)
73858044Sbrian{
73958044Sbrian  if (arg->argc == arg->argn + 1) {
74058044Sbrian    if (!strcasecmp(arg->argv[arg->argn], "reload"))
74158044Sbrian      ipcp_LoadDNS(&arg->bundle->ncp.ipcp);
74258044Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "restore"))
74358044Sbrian      ipcp_RestoreDNS(&arg->bundle->ncp.ipcp);
74458044Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "rewrite"))
74558044Sbrian      ipcp_WriteDNS(&arg->bundle->ncp.ipcp);
74658044Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "readonly"))
74758044Sbrian      arg->bundle->ncp.ipcp.ns.writable = 0;
74858044Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "writable"))
74958044Sbrian      arg->bundle->ncp.ipcp.ns.writable = 1;
75058044Sbrian    else
75158044Sbrian      return -1;
75258044Sbrian
75358044Sbrian    return 0;
75458044Sbrian  }
75558044Sbrian
75658044Sbrian  return -1;
75758044Sbrian}
75858044Sbrian
75950059Sbrian#ifndef NONAT
76058867Sbrianstatic struct cmdtab const NatCommands[] =
76140561Sbrian{
76250059Sbrian  {"addr", NULL, nat_RedirectAddr, LOCAL_AUTH,
763134789Sbrian   "static address translation", "nat addr [addr_local addr_alias]", NULL},
76458867Sbrian  {"deny_incoming", NULL, NatOption, LOCAL_AUTH,
76550059Sbrian   "stop incoming connections", "nat deny_incoming yes|no",
76640561Sbrian   (const void *) PKT_ALIAS_DENY_INCOMING},
76758867Sbrian  {"enable", NULL, NatEnable, LOCAL_AUTH,
768134789Sbrian   "enable NAT", "nat enable yes|no", NULL},
76958867Sbrian  {"log", NULL, NatOption, LOCAL_AUTH,
77050059Sbrian   "log NAT link creation", "nat log yes|no",
77140561Sbrian   (const void *) PKT_ALIAS_LOG},
77250059Sbrian  {"port", NULL, nat_RedirectPort, LOCAL_AUTH, "port redirection",
773134789Sbrian   "nat port proto localaddr:port[-port] aliasport[-aliasport]", NULL},
77479433Sbrian  {"proto", NULL, nat_RedirectProto, LOCAL_AUTH, "protocol redirection",
775134789Sbrian   "nat proto proto localIP [publicIP [remoteIP]]", NULL},
77650059Sbrian  {"proxy", NULL, nat_ProxyRule, LOCAL_AUTH,
777134789Sbrian   "proxy control", "nat proxy server host[:port] ...", NULL},
77881033Sbrian#ifndef NO_FW_PUNCH
77981033Sbrian  {"punch_fw", NULL, nat_PunchFW, LOCAL_AUTH,
780134789Sbrian   "firewall control", "nat punch_fw [base count]", NULL},
78181033Sbrian#endif
782120372Smarcus  {"skinny_port", NULL, nat_SkinnyPort, LOCAL_AUTH,
783134789Sbrian   "TCP port used by Skinny Station protocol", "nat skinny_port [port]", NULL},
78458867Sbrian  {"same_ports", NULL, NatOption, LOCAL_AUTH,
78550059Sbrian   "try to leave port numbers unchanged", "nat same_ports yes|no",
78640561Sbrian   (const void *) PKT_ALIAS_SAME_PORTS},
78758867Sbrian  {"target", NULL, nat_SetTarget, LOCAL_AUTH,
788134789Sbrian   "Default address for incoming connections", "nat target addr", NULL},
78958867Sbrian  {"unregistered_only", NULL, NatOption, LOCAL_AUTH,
79050059Sbrian   "translate unregistered (private) IP address space only",
79150059Sbrian   "nat unregistered_only yes|no",
79240561Sbrian   (const void *) PKT_ALIAS_UNREGISTERED_ONLY},
79358867Sbrian  {"use_sockets", NULL, NatOption, LOCAL_AUTH,
79450059Sbrian   "allocate host sockets", "nat use_sockets yes|no",
79540561Sbrian   (const void *) PKT_ALIAS_USE_SOCKETS},
79640561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
79758867Sbrian   "Display this message", "nat help|? [command]", NatCommands},
798134789Sbrian  {NULL, NULL, NULL, 0, NULL, NULL, NULL},
79940561Sbrian};
80040561Sbrian#endif
80140561Sbrian
80240561Sbrianstatic struct cmdtab const AllowCommands[] = {
80340561Sbrian  {"modes", "mode", AllowModes, LOCAL_AUTH,
804134789Sbrian  "Only allow certain ppp modes", "allow modes mode...", NULL},
80540561Sbrian  {"users", "user", AllowUsers, LOCAL_AUTH,
806134789Sbrian  "Only allow ppp access to certain users", "allow users logname...", NULL},
80740561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
80840561Sbrian  "Display this message", "allow help|? [command]", AllowCommands},
809134789Sbrian  {NULL, NULL, NULL, 0, NULL, NULL, NULL},
81040561Sbrian};
81140561Sbrian
81240561Sbrianstatic struct cmdtab const IfaceCommands[] =
81340561Sbrian{
81440561Sbrian  {"add", NULL, IfaceAddCommand, LOCAL_AUTH,
81540561Sbrian   "Add iface address", "iface add addr[/bits| mask] peer", NULL},
81640561Sbrian  {NULL, "add!", IfaceAddCommand, LOCAL_AUTH,
81740561Sbrian   "Add or change an iface address", "iface add! addr[/bits| mask] peer",
81840561Sbrian   (void *)1},
81940561Sbrian  {"clear", NULL, IfaceClearCommand, LOCAL_AUTH,
820134789Sbrian   "Clear iface address(es)", "iface clear [INET | INET6]", NULL},
82140561Sbrian  {"delete", "rm", IfaceDeleteCommand, LOCAL_AUTH,
82240561Sbrian   "Delete iface address", "iface delete addr", NULL},
82340561Sbrian  {NULL, "rm!", IfaceDeleteCommand, LOCAL_AUTH,
82440561Sbrian   "Delete iface address", "iface delete addr", (void *)1},
82540561Sbrian  {NULL, "delete!", IfaceDeleteCommand, LOCAL_AUTH,
82640561Sbrian   "Delete iface address", "iface delete addr", (void *)1},
827218397Sbrian  {"name", NULL, IfaceNameCommand, LOCAL_AUTH,
828218397Sbrian    "Set iface name", "iface name name", NULL},
829218397Sbrian  {"description", NULL, iface_Descr, LOCAL_AUTH,
830218397Sbrian    "Set iface description", "iface description text", NULL},
83140561Sbrian  {"show", NULL, iface_Show, LOCAL_AUTH,
832134789Sbrian   "Show iface address(es)", "iface show", NULL},
83340561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
83450059Sbrian   "Display this message", "nat help|? [command]", IfaceCommands},
835134789Sbrian  {NULL, NULL, NULL, 0, NULL, NULL, NULL},
83640561Sbrian};
83740561Sbrian
83830715Sbrianstatic struct cmdtab const Commands[] = {
83936285Sbrian  {"accept", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
840134789Sbrian  "accept option request", "accept option ..", NULL},
84128679Sbrian  {"add", NULL, AddCommand, LOCAL_AUTH,
84232109Sbrian  "add route", "add dest mask gateway", NULL},
84336285Sbrian  {NULL, "add!", AddCommand, LOCAL_AUTH,
84432109Sbrian  "add or change route", "add! dest mask gateway", (void *)1},
84540561Sbrian  {"allow", "auth", RunListCommand, LOCAL_AUTH,
84640561Sbrian  "Allow ppp access", "allow users|modes ....", AllowCommands},
84728679Sbrian  {"bg", "!bg", BgShellCommand, LOCAL_AUTH,
848134789Sbrian  "Run a background command", "[!]bg command", NULL},
84936934Sbrian  {"clear", NULL, ClearCommand, LOCAL_AUTH | LOCAL_CX_OPT,
85046686Sbrian  "Clear throughput statistics",
851134789Sbrian  "clear ipcp|ipv6cp|physical [current|overall|peak]...", NULL},
85236285Sbrian  {"clone", NULL, CloneCommand, LOCAL_AUTH | LOCAL_CX,
853134789Sbrian  "Clone a link", "clone newname...", NULL},
85436285Sbrian  {"close", NULL, CloseCommand, LOCAL_AUTH | LOCAL_CX_OPT,
855134789Sbrian  "Close an FSM", "close [lcp|ccp]", NULL},
85628679Sbrian  {"delete", NULL, DeleteCommand, LOCAL_AUTH,
85732109Sbrian  "delete route", "delete dest", NULL},
85836285Sbrian  {NULL, "delete!", DeleteCommand, LOCAL_AUTH,
85932109Sbrian  "delete a route if it exists", "delete! dest", (void *)1},
86036285Sbrian  {"deny", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
861134789Sbrian  "Deny option request", "deny option ..", NULL},
86236285Sbrian  {"dial", "call", DialCommand, LOCAL_AUTH | LOCAL_CX_OPT,
86340797Sbrian  "Dial and login", "dial|call [system ...]", NULL},
86436285Sbrian  {"disable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
865134789Sbrian  "Disable option", "disable option ..", NULL},
86636285Sbrian  {"down", NULL, DownCommand, LOCAL_AUTH | LOCAL_CX_OPT,
867134789Sbrian  "Generate a down event", "down [ccp|lcp]", NULL},
86836285Sbrian  {"enable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
869134789Sbrian  "Enable option", "enable option ..", NULL},
87063484Sbrian  {"ident", NULL, IdentCommand, LOCAL_AUTH | LOCAL_CX,
871134789Sbrian  "Set the link identity", "ident text...", NULL},
87240561Sbrian  {"iface", "interface", RunListCommand, LOCAL_AUTH,
87340561Sbrian  "interface control", "iface option ...", IfaceCommands},
87436285Sbrian  {"link", "datalink", LinkCommand, LOCAL_AUTH,
875134789Sbrian  "Link specific commands", "link name command ...", NULL},
87637008Sbrian  {"load", NULL, LoadCommand, LOCAL_AUTH | LOCAL_CX_OPT,
877134789Sbrian  "Load settings", "load [system ...]", NULL},
87885991Sbrian  {"log", NULL, LogCommand, LOCAL_AUTH | LOCAL_CX_OPT,
879134789Sbrian  "log information", "log word ...", NULL},
88050059Sbrian#ifndef NONAT
88150059Sbrian  {"nat", "alias", RunListCommand, LOCAL_AUTH,
88258867Sbrian  "NAT control", "nat option yes|no", NatCommands},
88350059Sbrian#endif
88436285Sbrian  {"open", NULL, OpenCommand, LOCAL_AUTH | LOCAL_CX_OPT,
88537955Sbrian  "Open an FSM", "open! [lcp|ccp|ipcp]", (void *)1},
88636285Sbrian  {"passwd", NULL, PasswdCommand, LOCAL_NO_AUTH,
887134789Sbrian  "Password for manipulation", "passwd LocalPassword", NULL},
88836285Sbrian  {"quit", "bye", QuitCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
889134789Sbrian  "Quit PPP program", "quit|bye [all]", NULL},
89036285Sbrian  {"remove", "rm", RemoveCommand, LOCAL_AUTH | LOCAL_CX,
891134789Sbrian  "Remove a link", "remove", NULL},
89236285Sbrian  {"rename", "mv", RenameCommand, LOCAL_AUTH | LOCAL_CX,
893134789Sbrian  "Rename a link", "rename name", NULL},
89458044Sbrian  {"resolv", NULL, ResolvCommand, LOCAL_AUTH,
895134789Sbrian  "Manipulate resolv.conf", "resolv readonly|reload|restore|rewrite|writable",
896134789Sbrian  NULL},
89728679Sbrian  {"save", NULL, SaveCommand, LOCAL_AUTH,
898134789Sbrian  "Save settings", "save", NULL},
89963484Sbrian  {"sendident", NULL, SendIdentification, LOCAL_AUTH | LOCAL_CX,
900134789Sbrian  "Transmit the link identity", "sendident", NULL},
90136285Sbrian  {"set", "setup", SetCommand, LOCAL_AUTH | LOCAL_CX_OPT,
902134789Sbrian  "Set parameters", "set[up] var value", NULL},
90328679Sbrian  {"shell", "!", FgShellCommand, LOCAL_AUTH,
904134789Sbrian  "Run a subshell", "shell|! [sh command]", NULL},
90536285Sbrian  {"show", NULL, ShowCommand, LOCAL_AUTH | LOCAL_CX_OPT,
906134789Sbrian  "Show status and stats", "show var", NULL},
90736285Sbrian  {"term", NULL, TerminalCommand, LOCAL_AUTH | LOCAL_CX,
908134789Sbrian  "Enter terminal mode", "term", NULL},
90928679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
91031343Sbrian  "Display this message", "help|? [command]", Commands},
911134789Sbrian  {NULL, NULL, NULL, 0, NULL, NULL, NULL},
9126059Samurai};
9136059Samurai
91428536Sbrianstatic int
91531343SbrianShowEscape(struct cmdargs const *arg)
9166059Samurai{
91736285Sbrian  if (arg->cx->physical->async.cfg.EscMap[32]) {
91836285Sbrian    int code, bit;
91936285Sbrian    const char *sep = "";
9206059Samurai
92126516Sbrian    for (code = 0; code < 32; code++)
92236285Sbrian      if (arg->cx->physical->async.cfg.EscMap[code])
92328679Sbrian	for (bit = 0; bit < 8; bit++)
92436285Sbrian	  if (arg->cx->physical->async.cfg.EscMap[code] & (1 << bit)) {
92536285Sbrian	    prompt_Printf(arg->prompt, "%s0x%02x", sep, (code << 3) + bit);
92636285Sbrian            sep = ", ";
92736285Sbrian          }
92836285Sbrian    prompt_Printf(arg->prompt, "\n");
9296059Samurai  }
93031077Sbrian  return 0;
9316059Samurai}
9326059Samurai
93328679Sbrianstatic int
93436285SbrianShowTimerList(struct cmdargs const *arg)
9356059Samurai{
93636285Sbrian  timer_Show(0, arg->prompt);
93731077Sbrian  return 0;
9386059Samurai}
9396059Samurai
94028679Sbrianstatic int
94131343SbrianShowStopped(struct cmdargs const *arg)
94228327Sbrian{
94336285Sbrian  prompt_Printf(arg->prompt, " Stopped Timer:  LCP: ");
94436285Sbrian  if (!arg->cx->physical->link.lcp.fsm.StoppedTimer.load)
94536285Sbrian    prompt_Printf(arg->prompt, "Disabled");
94628327Sbrian  else
94736285Sbrian    prompt_Printf(arg->prompt, "%ld secs",
94836285Sbrian                  arg->cx->physical->link.lcp.fsm.StoppedTimer.load / SECTICKS);
94928461Sbrian
95036285Sbrian  prompt_Printf(arg->prompt, ", CCP: ");
95136285Sbrian  if (!arg->cx->physical->link.ccp.fsm.StoppedTimer.load)
95236285Sbrian    prompt_Printf(arg->prompt, "Disabled");
95328461Sbrian  else
95436285Sbrian    prompt_Printf(arg->prompt, "%ld secs",
95536285Sbrian                  arg->cx->physical->link.ccp.fsm.StoppedTimer.load / SECTICKS);
95628461Sbrian
95736285Sbrian  prompt_Printf(arg->prompt, "\n");
95828461Sbrian
95931077Sbrian  return 0;
96028327Sbrian}
96128327Sbrian
96228679Sbrianstatic int
96331343SbrianShowVersion(struct cmdargs const *arg)
9646059Samurai{
965162063Sbrian  prompt_Printf(arg->prompt, "PPP Version %s\n", Version);
96631077Sbrian  return 0;
9676059Samurai}
9686059Samurai
96928679Sbrianstatic int
97036285SbrianShowProtocolStats(struct cmdargs const *arg)
97126326Sbrian{
97236285Sbrian  struct link *l = command_ChooseLink(arg);
97326326Sbrian
97436285Sbrian  prompt_Printf(arg->prompt, "%s:\n", l->name);
97536285Sbrian  link_ReportProtocolStatus(l, arg->prompt);
97631077Sbrian  return 0;
97726326Sbrian}
97826326Sbrian
97930715Sbrianstatic struct cmdtab const ShowCommands[] = {
98036285Sbrian  {"bundle", NULL, bundle_ShowStatus, LOCAL_AUTH,
981134789Sbrian  "bundle details", "show bundle", NULL},
98236285Sbrian  {"ccp", NULL, ccp_ReportStatus, LOCAL_AUTH | LOCAL_CX_OPT,
983134789Sbrian  "CCP status", "show cpp", NULL},
98436285Sbrian  {"compress", NULL, sl_Show, LOCAL_AUTH,
985134789Sbrian  "VJ compression stats", "show compress", NULL},
98636285Sbrian  {"escape", NULL, ShowEscape, LOCAL_AUTH | LOCAL_CX,
987134789Sbrian  "escape characters", "show escape", NULL},
98836285Sbrian  {"filter", NULL, filter_Show, LOCAL_AUTH,
989134789Sbrian  "packet filters", "show filter [in|out|dial|alive]", NULL},
99036285Sbrian  {"hdlc", NULL, hdlc_ReportStatus, LOCAL_AUTH | LOCAL_CX,
991134789Sbrian  "HDLC errors", "show hdlc", NULL},
99240561Sbrian  {"iface", "interface", iface_Show, LOCAL_AUTH,
993134789Sbrian  "Interface status", "show iface", NULL},
99436285Sbrian  {"ipcp", NULL, ipcp_Show, LOCAL_AUTH,
995134789Sbrian  "IPCP status", "show ipcp", NULL},
99681634Sbrian#ifndef NOINET6
99781634Sbrian  {"ipv6cp", NULL, ipv6cp_Show, LOCAL_AUTH,
998134789Sbrian  "IPV6CP status", "show ipv6cp", NULL},
99981634Sbrian#endif
100047211Sbrian  {"layers", NULL, link_ShowLayers, LOCAL_AUTH | LOCAL_CX_OPT,
1001134789Sbrian  "Protocol layers", "show layers", NULL},
100236285Sbrian  {"lcp", NULL, lcp_ReportStatus, LOCAL_AUTH | LOCAL_CX,
1003134789Sbrian  "LCP status", "show lcp", NULL},
100436285Sbrian  {"link", "datalink", datalink_Show, LOCAL_AUTH | LOCAL_CX,
1005134789Sbrian  "(high-level) link info", "show link", NULL},
100636285Sbrian  {"links", NULL, bundle_ShowLinks, LOCAL_AUTH,
1007134789Sbrian  "available link names", "show links", NULL},
100836285Sbrian  {"log", NULL, log_ShowLevel, LOCAL_AUTH,
1009134789Sbrian  "log levels", "show log", NULL},
101036285Sbrian  {"mem", NULL, mbuf_Show, LOCAL_AUTH,
1011134789Sbrian  "mbuf allocations", "show mem", NULL},
101281634Sbrian  {"ncp", NULL, ncp_Show, LOCAL_AUTH,
1013134789Sbrian  "NCP status", "show ncp", NULL},
101446686Sbrian  {"physical", NULL, physical_ShowStatus, LOCAL_AUTH | LOCAL_CX,
1015134789Sbrian  "(low-level) link info", "show physical", NULL},
101636285Sbrian  {"mp", "multilink", mp_ShowStatus, LOCAL_AUTH,
1017134789Sbrian  "multilink setup", "show mp", NULL},
101836285Sbrian  {"proto", NULL, ShowProtocolStats, LOCAL_AUTH | LOCAL_CX_OPT,
1019134789Sbrian  "protocol summary", "show proto", NULL},
102036285Sbrian  {"route", NULL, route_Show, LOCAL_AUTH,
1021134789Sbrian  "routing table", "show route", NULL},
102236285Sbrian  {"stopped", NULL, ShowStopped, LOCAL_AUTH | LOCAL_CX,
1023134789Sbrian  "STOPPED timeout", "show stopped", NULL},
102436285Sbrian  {"timers", NULL, ShowTimerList, LOCAL_AUTH,
1025134789Sbrian  "alarm timers", "show timers", NULL},
102628679Sbrian  {"version", NULL, ShowVersion, LOCAL_NO_AUTH | LOCAL_AUTH,
1027134789Sbrian  "version string", "show version", NULL},
102836285Sbrian  {"who", NULL, log_ShowWho, LOCAL_AUTH,
1029134789Sbrian  "client list", "show who", NULL},
103028679Sbrian  {"help", "?", HelpCommand, LOCAL_NO_AUTH | LOCAL_AUTH,
103131343Sbrian  "Display this message", "show help|? [command]", ShowCommands},
1032134789Sbrian  {NULL, NULL, NULL, 0, NULL, NULL, NULL},
10336059Samurai};
10346059Samurai
103530715Sbrianstatic struct cmdtab const *
103631343SbrianFindCommand(struct cmdtab const *cmds, const char *str, int *pmatch)
10376059Samurai{
103826516Sbrian  int nmatch;
103926516Sbrian  int len;
104028679Sbrian  struct cmdtab const *found;
10416059Samurai
104226516Sbrian  found = NULL;
104326516Sbrian  len = strlen(str);
104426516Sbrian  nmatch = 0;
10456059Samurai  while (cmds->func) {
104625566Sbrian    if (cmds->name && strncasecmp(str, cmds->name, len) == 0) {
104726516Sbrian      if (cmds->name[len] == '\0') {
104828679Sbrian	*pmatch = 1;
104928679Sbrian	return cmds;
105026516Sbrian      }
10516059Samurai      nmatch++;
10526059Samurai      found = cmds;
105328679Sbrian    } else if (cmds->alias && strncasecmp(str, cmds->alias, len) == 0) {
105426516Sbrian      if (cmds->alias[len] == '\0') {
105528679Sbrian	*pmatch = 1;
105628679Sbrian	return cmds;
105726516Sbrian      }
10586059Samurai      nmatch++;
10596059Samurai      found = cmds;
10606059Samurai    }
10616059Samurai    cmds++;
10626059Samurai  }
10636059Samurai  *pmatch = nmatch;
106426516Sbrian  return found;
10656059Samurai}
10666059Samurai
106736285Sbrianstatic const char *
106836285SbrianmkPrefix(int argc, char const *const *argv, char *tgt, int sz)
106936285Sbrian{
107036285Sbrian  int f, tlen, len;
107136285Sbrian
107236285Sbrian  tlen = 0;
107336285Sbrian  for (f = 0; f < argc && tlen < sz - 2; f++) {
107436285Sbrian    if (f)
107536285Sbrian      tgt[tlen++] = ' ';
107636285Sbrian    len = strlen(argv[f]);
107736285Sbrian    if (len > sz - tlen - 1)
107836285Sbrian      len = sz - tlen - 1;
107936285Sbrian    strncpy(tgt+tlen, argv[f], len);
108036285Sbrian    tlen += len;
108136285Sbrian  }
108236285Sbrian  tgt[tlen] = '\0';
108336285Sbrian  return tgt;
108436285Sbrian}
108536285Sbrian
108630715Sbrianstatic int
108736285SbrianFindExec(struct bundle *bundle, struct cmdtab const *cmds, int argc, int argn,
108836285Sbrian         char const *const *argv, struct prompt *prompt, struct datalink *cx)
10896059Samurai{
109028679Sbrian  struct cmdtab const *cmd;
10916059Samurai  int val = 1;
10926059Samurai  int nmatch;
109331343Sbrian  struct cmdargs arg;
109436285Sbrian  char prefix[100];
10956059Samurai
109636285Sbrian  cmd = FindCommand(cmds, argv[argn], &nmatch);
10976059Samurai  if (nmatch > 1)
109836285Sbrian    log_Printf(LogWARN, "%s: Ambiguous command\n",
109936285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix));
110036285Sbrian  else if (cmd && (!prompt || (cmd->lauth & prompt->auth))) {
110136285Sbrian    if ((cmd->lauth & LOCAL_CX) && !cx)
110236285Sbrian      /* We've got no context, but we require it */
110336285Sbrian      cx = bundle2datalink(bundle, NULL);
110436285Sbrian
110536285Sbrian    if ((cmd->lauth & LOCAL_CX) && !cx)
110636285Sbrian      log_Printf(LogWARN, "%s: No context (use the `link' command)\n",
110736285Sbrian                mkPrefix(argn+1, argv, prefix, sizeof prefix));
110836285Sbrian    else {
110936285Sbrian      if (cx && !(cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
111036285Sbrian        log_Printf(LogWARN, "%s: Redundant context (%s) ignored\n",
111136285Sbrian                  mkPrefix(argn+1, argv, prefix, sizeof prefix), cx->name);
111236285Sbrian        cx = NULL;
111336285Sbrian      }
111436285Sbrian      arg.cmdtab = cmds;
111536285Sbrian      arg.cmd = cmd;
111636285Sbrian      arg.argc = argc;
111736285Sbrian      arg.argn = argn+1;
111836285Sbrian      arg.argv = argv;
111936285Sbrian      arg.bundle = bundle;
112036285Sbrian      arg.cx = cx;
112136285Sbrian      arg.prompt = prompt;
112236285Sbrian      val = (*cmd->func) (&arg);
112336285Sbrian    }
112431343Sbrian  } else
112536285Sbrian    log_Printf(LogWARN, "%s: Invalid command\n",
112636285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix));
112726516Sbrian
112826516Sbrian  if (val == -1)
112995258Sdes    log_Printf(LogWARN, "usage: %s\n", cmd->syntax);
113028679Sbrian  else if (val)
113136285Sbrian    log_Printf(LogWARN, "%s: Failed %d\n",
113236285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix), val);
113326516Sbrian
113426516Sbrian  return val;
11356059Samurai}
11366059Samurai
113737009Sbrianint
113858045Sbriancommand_Expand_Interpret(char *buff, int nb, char *argv[MAXARGS], int offset)
113958045Sbrian{
114058045Sbrian  char buff2[LINE_LEN-offset];
114158045Sbrian
114258045Sbrian  InterpretArg(buff, buff2);
114358045Sbrian  strncpy(buff, buff2, LINE_LEN - offset - 1);
114458045Sbrian  buff[LINE_LEN - offset - 1] = '\0';
114558045Sbrian
114658045Sbrian  return command_Interpret(buff, nb, argv);
114758045Sbrian}
114858045Sbrian
114958045Sbrianint
115037009Sbriancommand_Interpret(char *buff, int nb, char *argv[MAXARGS])
11516059Samurai{
11526059Samurai  char *cp;
11536059Samurai
11546059Samurai  if (nb > 0) {
11556059Samurai    cp = buff + strcspn(buff, "\r\n");
11566059Samurai    if (cp)
11576059Samurai      *cp = '\0';
115855145Sbrian    return MakeArgs(buff, argv, MAXARGS, PARSE_REDUCE);
115937009Sbrian  }
116037009Sbrian  return 0;
116131121Sbrian}
11626059Samurai
116331822Sbrianstatic int
1164134789Sbrianarghidden(char const *const *argv, int n)
116531822Sbrian{
116631822Sbrian  /* Is arg n of the given command to be hidden from the log ? */
116731828Sbrian
116831828Sbrian  /* set authkey xxxxx */
116931828Sbrian  /* set key xxxxx */
117031822Sbrian  if (n == 2 && !strncasecmp(argv[0], "se", 2) &&
117131822Sbrian      (!strncasecmp(argv[1], "authk", 5) || !strncasecmp(argv[1], "ke", 2)))
117231822Sbrian    return 1;
117331822Sbrian
117431828Sbrian  /* passwd xxxxx */
117531828Sbrian  if (n == 1 && !strncasecmp(argv[0], "p", 1))
117631828Sbrian    return 1;
117731828Sbrian
117836285Sbrian  /* set server port xxxxx .... */
117936285Sbrian  if (n == 3 && !strncasecmp(argv[0], "se", 2) &&
118036285Sbrian      !strncasecmp(argv[1], "se", 2))
118136285Sbrian    return 1;
118236285Sbrian
118331822Sbrian  return 0;
118431822Sbrian}
118531822Sbrian
118631121Sbrianvoid
118736285Sbriancommand_Run(struct bundle *bundle, int argc, char const *const *argv,
118837008Sbrian           struct prompt *prompt, const char *label, struct datalink *cx)
118931121Sbrian{
119031156Sbrian  if (argc > 0) {
119136285Sbrian    if (log_IsKept(LogCOMMAND)) {
119247844Sbrian      char buf[LINE_LEN];
1193134789Sbrian      int f;
1194134789Sbrian      size_t n;
119531156Sbrian
119631156Sbrian      if (label) {
119731962Sbrian        strncpy(buf, label, sizeof buf - 3);
119831962Sbrian        buf[sizeof buf - 3] = '\0';
119931156Sbrian        strcat(buf, ": ");
120047844Sbrian        n = strlen(buf);
120147844Sbrian      } else {
120247844Sbrian        *buf = '\0';
120347844Sbrian        n = 0;
120431156Sbrian      }
120547844Sbrian      buf[sizeof buf - 1] = '\0';	/* In case we run out of room in buf */
120647844Sbrian
120731156Sbrian      for (f = 0; f < argc; f++) {
120831962Sbrian        if (n < sizeof buf - 1 && f)
120931156Sbrian          buf[n++] = ' ';
1210134789Sbrian        if (arghidden(argv, f))
121136285Sbrian          strncpy(buf+n, "********", sizeof buf - n - 1);
121231822Sbrian        else
121331962Sbrian          strncpy(buf+n, argv[f], sizeof buf - n - 1);
121431156Sbrian        n += strlen(buf+n);
121531156Sbrian      }
121636285Sbrian      log_Printf(LogCOMMAND, "%s\n", buf);
121731156Sbrian    }
121837008Sbrian    FindExec(bundle, Commands, argc, 0, argv, prompt, cx);
121931156Sbrian  }
12206059Samurai}
12216059Samurai
122254914Sbrianint
122336285Sbriancommand_Decode(struct bundle *bundle, char *buff, int nb, struct prompt *prompt,
122436285Sbrian              const char *label)
122531121Sbrian{
122631121Sbrian  int argc;
122737009Sbrian  char *argv[MAXARGS];
122831121Sbrian
122958045Sbrian  if ((argc = command_Expand_Interpret(buff, nb, argv, 0)) < 0)
123054914Sbrian    return 0;
123154914Sbrian
123237008Sbrian  command_Run(bundle, argc, (char const *const *)argv, prompt, label, NULL);
123354914Sbrian  return 1;
123431121Sbrian}
123531121Sbrian
12366059Samuraistatic int
123731343SbrianShowCommand(struct cmdargs const *arg)
12386059Samurai{
123936285Sbrian  if (!arg->prompt)
124036285Sbrian    log_Printf(LogWARN, "show: Cannot show without a prompt\n");
124136285Sbrian  else if (arg->argc > arg->argn)
124236285Sbrian    FindExec(arg->bundle, ShowCommands, arg->argc, arg->argn, arg->argv,
124336285Sbrian             arg->prompt, arg->cx);
12446059Samurai  else
124536285Sbrian    prompt_Printf(arg->prompt, "Use ``show ?'' to get a list.\n");
124626516Sbrian
124726516Sbrian  return 0;
12486059Samurai}
12496059Samurai
12506059Samuraistatic int
125131343SbrianTerminalCommand(struct cmdargs const *arg)
12526059Samurai{
125336285Sbrian  if (!arg->prompt) {
125436285Sbrian    log_Printf(LogWARN, "term: Need a prompt\n");
125526516Sbrian    return 1;
12566059Samurai  }
125736285Sbrian
125836285Sbrian  if (arg->cx->physical->link.lcp.fsm.state > ST_CLOSED) {
125936285Sbrian    prompt_Printf(arg->prompt, "LCP state is [%s]\n",
126036285Sbrian                  State2Nam(arg->cx->physical->link.lcp.fsm.state));
126136285Sbrian    return 1;
12626059Samurai  }
126336285Sbrian
126436285Sbrian  datalink_Up(arg->cx, 0, 0);
126536285Sbrian  prompt_TtyTermMode(arg->prompt, arg->cx);
126636285Sbrian  return 0;
12676059Samurai}
12686059Samurai
12696059Samuraistatic int
127031343SbrianQuitCommand(struct cmdargs const *arg)
12716059Samurai{
127236285Sbrian  if (!arg->prompt || prompt_IsController(arg->prompt) ||
127336285Sbrian      (arg->argc > arg->argn && !strcasecmp(arg->argv[arg->argn], "all") &&
127436285Sbrian       (arg->prompt->auth & LOCAL_AUTH)))
1275134789Sbrian    Cleanup();
127636285Sbrian  if (arg->prompt)
127736285Sbrian    prompt_Destroy(arg->prompt, 1);
127826516Sbrian
127926516Sbrian  return 0;
12806059Samurai}
12816059Samurai
12826059Samuraistatic int
128336285SbrianOpenCommand(struct cmdargs const *arg)
12846059Samurai{
128537160Sbrian  if (arg->argc == arg->argn)
128637993Sbrian    bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1);
128737160Sbrian  else if (arg->argc == arg->argn + 1) {
128837160Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp")) {
128937385Sbrian      struct datalink *cx = arg->cx ?
129037385Sbrian        arg->cx : bundle2datalink(arg->bundle, NULL);
129137385Sbrian      if (cx) {
129237385Sbrian        if (cx->physical->link.lcp.fsm.state == ST_OPENED)
129337385Sbrian          fsm_Reopen(&cx->physical->link.lcp.fsm);
129437160Sbrian        else
129537993Sbrian          bundle_Open(arg->bundle, cx->name, PHYS_ALL, 1);
129637160Sbrian      } else
129737160Sbrian        log_Printf(LogWARN, "open lcp: You must specify a link\n");
129837160Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) {
129937160Sbrian      struct fsm *fp;
13006059Samurai
130137210Sbrian      fp = &command_ChooseLink(arg)->ccp.fsm;
130237160Sbrian      if (fp->link->lcp.fsm.state != ST_OPENED)
130337160Sbrian        log_Printf(LogWARN, "open: LCP must be open before opening CCP\n");
130437160Sbrian      else if (fp->state == ST_OPENED)
130537160Sbrian        fsm_Reopen(fp);
130637160Sbrian      else {
130737160Sbrian        fp->open_mode = 0;	/* Not passive any more */
130837160Sbrian        if (fp->state == ST_STOPPED) {
130937160Sbrian          fsm_Down(fp);
131037160Sbrian          fsm_Up(fp);
131137160Sbrian        } else {
131237160Sbrian          fsm_Up(fp);
131337160Sbrian          fsm_Open(fp);
131437160Sbrian        }
131536285Sbrian      }
131637160Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ipcp")) {
131737160Sbrian      if (arg->cx)
131837160Sbrian        log_Printf(LogWARN, "open ipcp: You need not specify a link\n");
131937160Sbrian      if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED)
132037160Sbrian        fsm_Reopen(&arg->bundle->ncp.ipcp.fsm);
132137160Sbrian      else
132237993Sbrian        bundle_Open(arg->bundle, NULL, PHYS_ALL, 1);
132337160Sbrian    } else
132437160Sbrian      return -1;
132536285Sbrian  } else
132636285Sbrian    return -1;
132736285Sbrian
132826516Sbrian  return 0;
13296059Samurai}
13306059Samurai
133125067Sbrianstatic int
133236285SbrianCloseCommand(struct cmdargs const *arg)
13336059Samurai{
133437007Sbrian  if (arg->argc == arg->argn)
133537007Sbrian    bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_STAYDOWN);
133637007Sbrian  else if (arg->argc == arg->argn + 1) {
133737007Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp"))
133837007Sbrian      bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_LCP);
133937007Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "ccp") ||
134037007Sbrian             !strcasecmp(arg->argv[arg->argn], "ccp!")) {
134137007Sbrian      struct fsm *fp;
13426059Samurai
134337210Sbrian      fp = &command_ChooseLink(arg)->ccp.fsm;
134437007Sbrian      if (fp->state == ST_OPENED) {
134537007Sbrian        fsm_Close(fp);
134637007Sbrian        if (arg->argv[arg->argn][3] == '!')
134737007Sbrian          fp->open_mode = 0;		/* Stay ST_CLOSED */
134837007Sbrian        else
134937007Sbrian          fp->open_mode = OPEN_PASSIVE;	/* Wait for the peer to start */
135037007Sbrian      }
135137007Sbrian    } else
135236285Sbrian      return -1;
135336285Sbrian  } else
135436285Sbrian    return -1;
135536285Sbrian
135636285Sbrian  return 0;
13576059Samurai}
13586059Samurai
135925067Sbrianstatic int
136036285SbrianDownCommand(struct cmdargs const *arg)
136111336Samurai{
136237018Sbrian  if (arg->argc == arg->argn) {
136337018Sbrian      if (arg->cx)
136437018Sbrian        datalink_Down(arg->cx, CLOSE_STAYDOWN);
136537018Sbrian      else
136637018Sbrian        bundle_Down(arg->bundle, CLOSE_STAYDOWN);
136737018Sbrian  } else if (arg->argc == arg->argn + 1) {
136837018Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp")) {
136937018Sbrian      if (arg->cx)
137037018Sbrian        datalink_Down(arg->cx, CLOSE_LCP);
137137018Sbrian      else
137237018Sbrian        bundle_Down(arg->bundle, CLOSE_LCP);
137337018Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) {
137437018Sbrian      struct fsm *fp = arg->cx ? &arg->cx->physical->link.ccp.fsm :
137537018Sbrian                                 &arg->bundle->ncp.mp.link.ccp.fsm;
137637060Sbrian      fsm2initial(fp);
137737018Sbrian    } else
137837018Sbrian      return -1;
137936285Sbrian  } else
138036285Sbrian    return -1;
138136285Sbrian
138236285Sbrian  return 0;
138325067Sbrian}
138425067Sbrian
138525067Sbrianstatic int
138636285SbrianSetModemSpeed(struct cmdargs const *arg)
138725067Sbrian{
138836285Sbrian  long speed;
138936285Sbrian  char *end;
139011336Samurai
139136285Sbrian  if (arg->argc > arg->argn && *arg->argv[arg->argn]) {
139236285Sbrian    if (arg->argc > arg->argn+1) {
139354917Sbrian      log_Printf(LogWARN, "SetModemSpeed: Too many arguments\n");
139436285Sbrian      return -1;
139511336Samurai    }
139636285Sbrian    if (strcasecmp(arg->argv[arg->argn], "sync") == 0) {
139736285Sbrian      physical_SetSync(arg->cx->physical);
139836285Sbrian      return 0;
139936285Sbrian    }
140036285Sbrian    end = NULL;
140136285Sbrian    speed = strtol(arg->argv[arg->argn], &end, 10);
1402134789Sbrian    if (*end || speed < 0) {
140336285Sbrian      log_Printf(LogWARN, "SetModemSpeed: Bad argument \"%s\"",
140436285Sbrian                arg->argv[arg->argn]);
140536285Sbrian      return -1;
140636285Sbrian    }
140736285Sbrian    if (physical_SetSpeed(arg->cx->physical, speed))
140836285Sbrian      return 0;
140936285Sbrian    log_Printf(LogWARN, "%s: Invalid speed\n", arg->argv[arg->argn]);
141036285Sbrian  } else
141136285Sbrian    log_Printf(LogWARN, "SetModemSpeed: No speed specified\n");
141224939Sbrian
141326516Sbrian  return -1;
141411336Samurai}
141511336Samurai
141625067Sbrianstatic int
141731343SbrianSetStoppedTimeout(struct cmdargs const *arg)
141828327Sbrian{
141936285Sbrian  struct link *l = &arg->cx->physical->link;
142036285Sbrian
142136285Sbrian  l->lcp.fsm.StoppedTimer.load = 0;
142236285Sbrian  l->ccp.fsm.StoppedTimer.load = 0;
142336285Sbrian  if (arg->argc <= arg->argn+2) {
142436285Sbrian    if (arg->argc > arg->argn) {
142536285Sbrian      l->lcp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn]) * SECTICKS;
142636285Sbrian      if (arg->argc > arg->argn+1)
142736285Sbrian        l->ccp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn+1]) * SECTICKS;
142828461Sbrian    }
142928327Sbrian    return 0;
143028327Sbrian  }
143128327Sbrian  return -1;
143228327Sbrian}
143328327Sbrian
143428327Sbrianstatic int
143531343SbrianSetServer(struct cmdargs const *arg)
143626940Sbrian{
143726940Sbrian  int res = -1;
143826940Sbrian
143936285Sbrian  if (arg->argc > arg->argn && arg->argc < arg->argn+4) {
144031081Sbrian    const char *port, *passwd, *mask;
1441134789Sbrian    size_t mlen;
144231081Sbrian
144331081Sbrian    /* What's what ? */
144436285Sbrian    port = arg->argv[arg->argn];
144536285Sbrian    if (arg->argc == arg->argn + 2) {
144636285Sbrian      passwd = arg->argv[arg->argn+1];
144736285Sbrian      mask = NULL;
144836285Sbrian    } else if (arg->argc == arg->argn + 3) {
144936285Sbrian      passwd = arg->argv[arg->argn+1];
145036285Sbrian      mask = arg->argv[arg->argn+2];
145153125Sbrian      mlen = strlen(mask);
145253125Sbrian      if (mlen == 0 || mlen > 4 || strspn(mask, "01234567") != mlen ||
145353125Sbrian          (mlen == 4 && *mask != '0')) {
145453125Sbrian        log_Printf(LogWARN, "%s %s: %s: Invalid mask\n",
145553125Sbrian                   arg->argv[arg->argn - 2], arg->argv[arg->argn - 1], mask);
145631081Sbrian        return -1;
145753125Sbrian      }
145871764Sbrian    } else if (arg->argc != arg->argn + 1)
145971764Sbrian      return -1;
146071764Sbrian    else if (strcasecmp(port, "none") == 0) {
146171657Sbrian      if (server_Clear(arg->bundle))
146271657Sbrian        log_Printf(LogPHASE, "Disabled server socket\n");
146371657Sbrian      return 0;
146471657Sbrian    } else if (strcasecmp(port, "open") == 0) {
146571657Sbrian      switch (server_Reopen(arg->bundle)) {
146671657Sbrian        case SERVER_OK:
146771657Sbrian          return 0;
146871657Sbrian        case SERVER_FAILED:
146971764Sbrian          log_Printf(LogWARN, "Failed to reopen server port\n");
147071657Sbrian          return 1;
147171657Sbrian        case SERVER_UNSET:
147271764Sbrian          log_Printf(LogWARN, "Cannot reopen unset server socket\n");
147371657Sbrian          return 1;
147471657Sbrian        default:
147571657Sbrian          break;
147671657Sbrian      }
147771657Sbrian      return -1;
147871657Sbrian    } else if (strcasecmp(port, "closed") == 0) {
147936285Sbrian      if (server_Close(arg->bundle))
148071657Sbrian        log_Printf(LogPHASE, "Closed server socket\n");
148171657Sbrian      else
148271657Sbrian        log_Printf(LogWARN, "Server socket not open\n");
148371657Sbrian
148436285Sbrian      return 0;
148531081Sbrian    } else
148636285Sbrian      return -1;
148731081Sbrian
148871657Sbrian    strncpy(server.cfg.passwd, passwd, sizeof server.cfg.passwd - 1);
148971657Sbrian    server.cfg.passwd[sizeof server.cfg.passwd - 1] = '\0';
149031081Sbrian
149136285Sbrian    if (*port == '/') {
149231081Sbrian      mode_t imask;
149336285Sbrian      char *ptr, name[LINE_LEN + 12];
149428679Sbrian
149553125Sbrian      if (mask == NULL)
149631081Sbrian        imask = (mode_t)-1;
149753125Sbrian      else for (imask = mlen = 0; mask[mlen]; mlen++)
149853125Sbrian        imask = (imask * 8) + mask[mlen] - '0';
149936285Sbrian
150036285Sbrian      ptr = strstr(port, "%d");
150136285Sbrian      if (ptr) {
150236285Sbrian        snprintf(name, sizeof name, "%.*s%d%s",
150337210Sbrian                 (int)(ptr - port), port, arg->bundle->unit, ptr + 2);
150436285Sbrian        port = name;
150536285Sbrian      }
150636285Sbrian      res = server_LocalOpen(arg->bundle, port, imask);
150727346Sbrian    } else {
150836285Sbrian      int iport, add = 0;
150928679Sbrian
151031081Sbrian      if (mask != NULL)
151131081Sbrian        return -1;
151228679Sbrian
151336285Sbrian      if (*port == '+') {
151436285Sbrian        port++;
151536285Sbrian        add = 1;
151636285Sbrian      }
151731081Sbrian      if (strspn(port, "0123456789") != strlen(port)) {
151831081Sbrian        struct servent *s;
151931081Sbrian
152031081Sbrian        if ((s = getservbyname(port, "tcp")) == NULL) {
152131081Sbrian	  iport = 0;
152236285Sbrian	  log_Printf(LogWARN, "%s: Invalid port or service\n", port);
152328679Sbrian	} else
152431081Sbrian	  iport = ntohs(s->s_port);
152527346Sbrian      } else
152631081Sbrian        iport = atoi(port);
152736285Sbrian
152836285Sbrian      if (iport) {
152936285Sbrian        if (add)
153036285Sbrian          iport += arg->bundle->unit;
153136285Sbrian        res = server_TcpOpen(arg->bundle, iport);
153236285Sbrian      } else
153336285Sbrian        res = -1;
153427346Sbrian    }
153531081Sbrian  }
153626940Sbrian
153726940Sbrian  return res;
153826940Sbrian}
153926940Sbrian
154026940Sbrianstatic int
154131343SbrianSetEscape(struct cmdargs const *arg)
15426059Samurai{
15436059Samurai  int code;
154436285Sbrian  int argc = arg->argc - arg->argn;
154536285Sbrian  char const *const *argv = arg->argv + arg->argn;
15466059Samurai
15476059Samurai  for (code = 0; code < 33; code++)
154836285Sbrian    arg->cx->physical->async.cfg.EscMap[code] = 0;
154931343Sbrian
15506059Samurai  while (argc-- > 0) {
15516059Samurai    sscanf(*argv++, "%x", &code);
15526059Samurai    code &= 0xff;
155336285Sbrian    arg->cx->physical->async.cfg.EscMap[code >> 3] |= (1 << (code & 7));
155436285Sbrian    arg->cx->physical->async.cfg.EscMap[32] = 1;
15556059Samurai  }
155626516Sbrian  return 0;
15576059Samurai}
15586059Samurai
15596059Samuraistatic int
156031343SbrianSetInterfaceAddr(struct cmdargs const *arg)
15616059Samurai{
156281634Sbrian  struct ncp *ncp = &arg->bundle->ncp;
156381634Sbrian  struct ncpaddr ncpaddr;
156432267Sbrian  const char *hisaddr;
156532267Sbrian
156640561Sbrian  if (arg->argc > arg->argn + 4)
156740561Sbrian    return -1;
156840561Sbrian
156932267Sbrian  hisaddr = NULL;
157081634Sbrian  memset(&ncp->ipcp.cfg.my_range, '\0', sizeof ncp->ipcp.cfg.my_range);
157181634Sbrian  memset(&ncp->ipcp.cfg.peer_range, '\0', sizeof ncp->ipcp.cfg.peer_range);
157281634Sbrian  ncp->ipcp.cfg.HaveTriggerAddress = 0;
157381634Sbrian  ncp->ipcp.cfg.netmask.s_addr = INADDR_ANY;
157481634Sbrian  iplist_reset(&ncp->ipcp.cfg.peer_list);
157528394Sbrian
157636285Sbrian  if (arg->argc > arg->argn) {
157781634Sbrian    if (!ncprange_aton(&ncp->ipcp.cfg.my_range, ncp, arg->argv[arg->argn]))
157828679Sbrian      return 1;
157936285Sbrian    if (arg->argc > arg->argn+1) {
158036285Sbrian      hisaddr = arg->argv[arg->argn+1];
158136285Sbrian      if (arg->argc > arg->argn+2) {
158281634Sbrian        ncp->ipcp.ifmask = ncp->ipcp.cfg.netmask =
158381634Sbrian          GetIpAddr(arg->argv[arg->argn+2]);
158436285Sbrian	if (arg->argc > arg->argn+3) {
158581634Sbrian	  ncp->ipcp.cfg.TriggerAddress = GetIpAddr(arg->argv[arg->argn+3]);
158681634Sbrian	  ncp->ipcp.cfg.HaveTriggerAddress = 1;
15879440Samurai	}
15886059Samurai      }
15896059Samurai    }
15906059Samurai  }
159128394Sbrian
159240561Sbrian  /* 0.0.0.0 means any address (0 bits) */
1593132204Sbrian  ncprange_getaddr(&ncp->ipcp.cfg.my_range, &ncpaddr);
159481634Sbrian  ncpaddr_getip4(&ncpaddr, &ncp->ipcp.my_ip);
159581634Sbrian  if (ncp->ipcp.my_ip.s_addr == INADDR_ANY)
159681634Sbrian    ncprange_setwidth(&ncp->ipcp.cfg.my_range, 0);
159781634Sbrian  bundle_AdjustFilters(arg->bundle, &ncpaddr, NULL);
159836285Sbrian
159936285Sbrian  if (hisaddr && !ipcp_UseHisaddr(arg->bundle, hisaddr,
160036928Sbrian                                  arg->bundle->phys_type.all & PHYS_AUTO))
160132267Sbrian    return 4;
160231121Sbrian
160326516Sbrian  return 0;
16046059Samurai}
16056059Samurai
160618752Sjkhstatic int
160744305SbrianSetRetry(int argc, char const *const *argv, u_int *timeout, u_int *maxreq,
160844305Sbrian          u_int *maxtrm, int def)
160944305Sbrian{
161044305Sbrian  if (argc == 0) {
161144305Sbrian    *timeout = DEF_FSMRETRY;
161244305Sbrian    *maxreq = def;
161344305Sbrian    if (maxtrm != NULL)
161444305Sbrian      *maxtrm = def;
161544305Sbrian  } else {
161644305Sbrian    long l = atol(argv[0]);
161744305Sbrian
161844305Sbrian    if (l < MIN_FSMRETRY) {
161944305Sbrian      log_Printf(LogWARN, "%ld: Invalid FSM retry period - min %d\n",
162044305Sbrian                 l, MIN_FSMRETRY);
162144305Sbrian      return 1;
162244305Sbrian    } else
162344305Sbrian      *timeout = l;
162444305Sbrian
162544305Sbrian    if (argc > 1) {
162644305Sbrian      l = atol(argv[1]);
162744305Sbrian      if (l < 1) {
162844305Sbrian        log_Printf(LogWARN, "%ld: Invalid FSM REQ tries - changed to 1\n", l);
162944305Sbrian        l = 1;
163044305Sbrian      }
163144305Sbrian      *maxreq = l;
163244305Sbrian
163344305Sbrian      if (argc > 2 && maxtrm != NULL) {
163444305Sbrian        l = atol(argv[2]);
163544305Sbrian        if (l < 1) {
163644305Sbrian          log_Printf(LogWARN, "%ld: Invalid FSM TRM tries - changed to 1\n", l);
163744305Sbrian          l = 1;
163844305Sbrian        }
163944305Sbrian        *maxtrm = l;
164044305Sbrian      }
164144305Sbrian    }
164244305Sbrian  }
164344305Sbrian
164444305Sbrian  return 0;
164544305Sbrian}
164644305Sbrian
164744305Sbrianstatic int
164831343SbrianSetVariable(struct cmdargs const *arg)
16496059Samurai{
165037210Sbrian  long long_val, param = (long)arg->cmd->args;
165179119Sbrian  int mode, dummyint, f, first, res;
165278410Sbrian  u_short *change;
165331343Sbrian  const char *argp;
165436285Sbrian  struct datalink *cx = arg->cx;	/* LOCAL_CX uses this */
165536285Sbrian  struct link *l = command_ChooseLink(arg);	/* LOCAL_CX_OPT uses this */
165681634Sbrian  struct in_addr *ipaddr;
165781634Sbrian  struct ncpaddr ncpaddr[2];
16586059Samurai
165936285Sbrian  if (arg->argc > arg->argn)
166036285Sbrian    argp = arg->argv[arg->argn];
166126551Sbrian  else
166231343Sbrian    argp = "";
166326551Sbrian
166479119Sbrian  res = 0;
166579119Sbrian
166636285Sbrian  if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
166736285Sbrian    log_Printf(LogWARN, "set %s: No context (use the `link' command)\n",
166836285Sbrian              arg->cmd->name);
166936285Sbrian    return 1;
167036285Sbrian  } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
167136285Sbrian    log_Printf(LogWARN, "set %s: Redundant context (%s) ignored\n",
167236285Sbrian              arg->cmd->name, cx->name);
167336285Sbrian    cx = NULL;
167436285Sbrian  }
167536285Sbrian
167626551Sbrian  switch (param) {
167728679Sbrian  case VAR_AUTHKEY:
167850139Sbrian    strncpy(arg->bundle->cfg.auth.key, argp,
167950139Sbrian            sizeof arg->bundle->cfg.auth.key - 1);
168050139Sbrian    arg->bundle->cfg.auth.key[sizeof arg->bundle->cfg.auth.key - 1] = '\0';
168128679Sbrian    break;
168237210Sbrian
168328679Sbrian  case VAR_AUTHNAME:
168440622Sbrian    switch (bundle_Phase(arg->bundle)) {
168558880Sbrian      default:
168658880Sbrian        log_Printf(LogWARN, "Altering authname while at phase %s\n",
168758880Sbrian                   bundle_PhaseName(arg->bundle));
168858880Sbrian        /* drop through */
168940622Sbrian      case PHASE_DEAD:
169040622Sbrian      case PHASE_ESTABLISH:
169140622Sbrian        strncpy(arg->bundle->cfg.auth.name, argp,
169240622Sbrian                sizeof arg->bundle->cfg.auth.name - 1);
169340622Sbrian        arg->bundle->cfg.auth.name[sizeof arg->bundle->cfg.auth.name-1] = '\0';
169440622Sbrian        break;
169536285Sbrian    }
169628679Sbrian    break;
169737210Sbrian
169836285Sbrian  case VAR_AUTOLOAD:
169949434Sbrian    if (arg->argc == arg->argn + 3) {
170098243Sbrian      int v1, v2, v3;
170149434Sbrian      char *end;
170249434Sbrian
170349434Sbrian      v1 = strtol(arg->argv[arg->argn], &end, 0);
170449434Sbrian      if (v1 < 0 || *end) {
170549434Sbrian        log_Printf(LogWARN, "autoload: %s: Invalid min percentage\n",
170649434Sbrian                   arg->argv[arg->argn]);
170779119Sbrian        res = 1;
170879119Sbrian        break;
170936285Sbrian      }
171049434Sbrian
171149434Sbrian      v2 = strtol(arg->argv[arg->argn + 1], &end, 0);
171249434Sbrian      if (v2 < 0 || *end) {
171349434Sbrian        log_Printf(LogWARN, "autoload: %s: Invalid max percentage\n",
171449434Sbrian                   arg->argv[arg->argn + 1]);
171579119Sbrian        res = 1;
171679119Sbrian        break;
171749434Sbrian      }
171849434Sbrian      if (v2 < v1) {
171949434Sbrian        v3 = v1;
172049434Sbrian        v1 = v2;
172149434Sbrian        v2 = v3;
172249434Sbrian      }
172349434Sbrian
172449434Sbrian      v3 = strtol(arg->argv[arg->argn + 2], &end, 0);
172549434Sbrian      if (v3 <= 0 || *end) {
172649434Sbrian        log_Printf(LogWARN, "autoload: %s: Invalid throughput period\n",
172749434Sbrian                   arg->argv[arg->argn + 2]);
172879119Sbrian        res = 1;
172979119Sbrian        break;
173049434Sbrian      }
173149434Sbrian
173249434Sbrian      arg->bundle->ncp.mp.cfg.autoload.min = v1;
173349434Sbrian      arg->bundle->ncp.mp.cfg.autoload.max = v2;
173449434Sbrian      arg->bundle->ncp.mp.cfg.autoload.period = v3;
173549434Sbrian      mp_RestartAutoloadTimer(&arg->bundle->ncp.mp);
173636285Sbrian    } else {
173779119Sbrian      log_Printf(LogWARN, "Set autoload requires three arguments\n");
173879119Sbrian      res = 1;
173936285Sbrian    }
174036285Sbrian    break;
174137210Sbrian
174228679Sbrian  case VAR_DIAL:
174336285Sbrian    strncpy(cx->cfg.script.dial, argp, sizeof cx->cfg.script.dial - 1);
174436285Sbrian    cx->cfg.script.dial[sizeof cx->cfg.script.dial - 1] = '\0';
174528679Sbrian    break;
174637210Sbrian
174728679Sbrian  case VAR_LOGIN:
174836285Sbrian    strncpy(cx->cfg.script.login, argp, sizeof cx->cfg.script.login - 1);
174936285Sbrian    cx->cfg.script.login[sizeof cx->cfg.script.login - 1] = '\0';
175028679Sbrian    break;
175137210Sbrian
175236285Sbrian  case VAR_WINSIZE:
175336285Sbrian    if (arg->argc > arg->argn) {
175436285Sbrian      l->ccp.cfg.deflate.out.winsize = atoi(arg->argv[arg->argn]);
175536285Sbrian      if (l->ccp.cfg.deflate.out.winsize < 8 ||
175636285Sbrian          l->ccp.cfg.deflate.out.winsize > 15) {
175736285Sbrian          log_Printf(LogWARN, "%d: Invalid outgoing window size\n",
175836285Sbrian                    l->ccp.cfg.deflate.out.winsize);
175936285Sbrian          l->ccp.cfg.deflate.out.winsize = 15;
176036285Sbrian      }
176136285Sbrian      if (arg->argc > arg->argn+1) {
176236285Sbrian        l->ccp.cfg.deflate.in.winsize = atoi(arg->argv[arg->argn+1]);
176336285Sbrian        if (l->ccp.cfg.deflate.in.winsize < 8 ||
176436285Sbrian            l->ccp.cfg.deflate.in.winsize > 15) {
176536285Sbrian            log_Printf(LogWARN, "%d: Invalid incoming window size\n",
176636285Sbrian                      l->ccp.cfg.deflate.in.winsize);
176736285Sbrian            l->ccp.cfg.deflate.in.winsize = 15;
176836285Sbrian        }
176936285Sbrian      } else
177036285Sbrian        l->ccp.cfg.deflate.in.winsize = 0;
177136285Sbrian    } else {
177279119Sbrian      log_Printf(LogWARN, "No window size specified\n");
177379119Sbrian      res = 1;
177436285Sbrian    }
177536285Sbrian    break;
177637210Sbrian
177793418Sbrian#ifndef NODES
177878411Sbrian  case VAR_MPPE:
177979119Sbrian    if (arg->argc > arg->argn + 2) {
178079119Sbrian      res = -1;
178179119Sbrian      break;
178279119Sbrian    }
178378411Sbrian
178478411Sbrian    if (arg->argc == arg->argn) {
178578411Sbrian      l->ccp.cfg.mppe.keybits = 0;
178678411Sbrian      l->ccp.cfg.mppe.state = MPPE_ANYSTATE;
178778411Sbrian      l->ccp.cfg.mppe.required = 0;
178878411Sbrian      break;
178978411Sbrian    }
179078411Sbrian
179178411Sbrian    if (!strcmp(argp, "*"))
179278411Sbrian      long_val = 0;
179378411Sbrian    else {
179478411Sbrian      long_val = atol(argp);
179578411Sbrian      if (long_val != 40 && long_val != 56 && long_val != 128) {
179678411Sbrian        log_Printf(LogWARN, "%s: Invalid bits value\n", argp);
179779119Sbrian        res = -1;
179879119Sbrian        break;
179967910Sbrian      }
180067910Sbrian    }
180178411Sbrian
180278411Sbrian    if (arg->argc == arg->argn + 2) {
180378411Sbrian      if (!strcmp(arg->argv[arg->argn + 1], "*"))
180478411Sbrian        l->ccp.cfg.mppe.state = MPPE_ANYSTATE;
180578411Sbrian      else if (!strcasecmp(arg->argv[arg->argn + 1], "stateless"))
180678411Sbrian        l->ccp.cfg.mppe.state = MPPE_STATELESS;
180779370Sbrian      else if (!strcasecmp(arg->argv[arg->argn + 1], "stateful"))
180878411Sbrian        l->ccp.cfg.mppe.state = MPPE_STATEFUL;
180978411Sbrian      else {
181078411Sbrian        log_Printf(LogWARN, "%s: Invalid state value\n",
181178411Sbrian                   arg->argv[arg->argn + 1]);
181279119Sbrian        res = -1;
181379119Sbrian        break;
181478411Sbrian      }
181578411Sbrian    } else
181678411Sbrian      l->ccp.cfg.mppe.state = MPPE_ANYSTATE;
181778411Sbrian    l->ccp.cfg.mppe.keybits = long_val;
181878411Sbrian    l->ccp.cfg.mppe.required = 1;
181967910Sbrian    break;
182067910Sbrian#endif
182167910Sbrian
182228679Sbrian  case VAR_DEVICE:
182336285Sbrian    physical_SetDeviceList(cx->physical, arg->argc - arg->argn,
182436285Sbrian                           arg->argv + arg->argn);
182536285Sbrian    break;
182637210Sbrian
182736285Sbrian  case VAR_ACCMAP:
182836285Sbrian    if (arg->argc > arg->argn) {
182937210Sbrian      u_long ulong_val;
183036285Sbrian      sscanf(argp, "%lx", &ulong_val);
183137210Sbrian      cx->physical->link.lcp.cfg.accmap = (u_int32_t)ulong_val;
183236285Sbrian    } else {
183379119Sbrian      log_Printf(LogWARN, "No accmap specified\n");
183479119Sbrian      res = 1;
183536285Sbrian    }
183636285Sbrian    break;
183737210Sbrian
183836285Sbrian  case VAR_MODE:
183936285Sbrian    mode = Nam2mode(argp);
184036285Sbrian    if (mode == PHYS_NONE || mode == PHYS_ALL) {
184136285Sbrian      log_Printf(LogWARN, "%s: Invalid mode\n", argp);
184279119Sbrian      res = -1;
184379119Sbrian      break;
184436285Sbrian    }
184536285Sbrian    bundle_SetMode(arg->bundle, cx, mode);
184636285Sbrian    break;
184737210Sbrian
184836285Sbrian  case VAR_MRRU:
184940622Sbrian    switch (bundle_Phase(arg->bundle)) {
185040622Sbrian      case PHASE_DEAD:
185140622Sbrian        break;
185240622Sbrian      case PHASE_ESTABLISH:
185340622Sbrian        /* Make sure none of our links are DATALINK_LCP or greater */
185440622Sbrian        if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) {
1855228990Suqs          log_Printf(LogWARN, "mrru: Only changeable before LCP negotiations\n");
185679119Sbrian          res = 1;
185779119Sbrian          break;
185840622Sbrian        }
185940622Sbrian        break;
186040622Sbrian      default:
1861228990Suqs        log_Printf(LogWARN, "mrru: Only changeable at phase DEAD/ESTABLISH\n");
186279119Sbrian        res = 1;
186379119Sbrian        break;
186429696Sbrian    }
186579119Sbrian    if (res != 0)
186679119Sbrian      break;
186737210Sbrian    long_val = atol(argp);
186837210Sbrian    if (long_val && long_val < MIN_MRU) {
186937210Sbrian      log_Printf(LogWARN, "MRRU %ld: too small - min %d\n", long_val, MIN_MRU);
187079119Sbrian      res = 1;
187179119Sbrian      break;
187237210Sbrian    } else if (long_val > MAX_MRU) {
187337210Sbrian      log_Printf(LogWARN, "MRRU %ld: too big - max %d\n", long_val, MAX_MRU);
187479119Sbrian      res = 1;
187579119Sbrian      break;
187637210Sbrian    } else
187737210Sbrian      arg->bundle->ncp.mp.cfg.mrru = long_val;
187828679Sbrian    break;
187937210Sbrian
188036285Sbrian  case VAR_MRU:
188179163Sbrian    long_val = 0;	/* silence gcc */
188279163Sbrian    change = NULL;	/* silence gcc */
188378410Sbrian    switch(arg->argc - arg->argn) {
188478410Sbrian    case 1:
188579119Sbrian      if (argp[strspn(argp, "0123456789")] != '\0') {
188679119Sbrian        res = -1;
188779119Sbrian        break;
188879119Sbrian      }
188979119Sbrian      /*FALLTHRU*/
189078410Sbrian    case 0:
189178410Sbrian      long_val = atol(argp);
189278410Sbrian      change = &l->lcp.cfg.mru;
189378410Sbrian      if (long_val > l->lcp.cfg.max_mru) {
189478410Sbrian        log_Printf(LogWARN, "MRU %ld: too large - max set to %d\n", long_val,
189578410Sbrian                   l->lcp.cfg.max_mru);
189679119Sbrian        res = 1;
189779119Sbrian        break;
189878410Sbrian      }
189978410Sbrian      break;
190078410Sbrian    case 2:
190179119Sbrian      if (strcasecmp(argp, "max") && strcasecmp(argp, "maximum")) {
190279119Sbrian        res = -1;
190379119Sbrian        break;
190479119Sbrian      }
190578410Sbrian      long_val = atol(arg->argv[arg->argn + 1]);
190678410Sbrian      change = &l->lcp.cfg.max_mru;
190778410Sbrian      if (long_val > MAX_MRU) {
190878410Sbrian        log_Printf(LogWARN, "MRU %ld: too large - maximum is %d\n", long_val,
190978410Sbrian                   MAX_MRU);
191079119Sbrian        res = 1;
191179119Sbrian        break;
191278410Sbrian      }
191378410Sbrian      break;
191478410Sbrian    default:
191579119Sbrian      res = -1;
191679119Sbrian      break;
191778410Sbrian    }
191879119Sbrian    if (res != 0)
191979119Sbrian      break;
192078410Sbrian
192137210Sbrian    if (long_val == 0)
192280385Sbrian      *change = 0;
192337210Sbrian    else if (long_val < MIN_MRU) {
192437210Sbrian      log_Printf(LogWARN, "MRU %ld: too small - min %d\n", long_val, MIN_MRU);
192579119Sbrian      res = 1;
192679119Sbrian      break;
192737210Sbrian    } else if (long_val > MAX_MRU) {
192837210Sbrian      log_Printf(LogWARN, "MRU %ld: too big - max %d\n", long_val, MAX_MRU);
192979119Sbrian      res = 1;
193079119Sbrian      break;
193137210Sbrian    } else
193278410Sbrian      *change = long_val;
193378410Sbrian    if (l->lcp.cfg.mru > *change)
193478410Sbrian      l->lcp.cfg.mru = *change;
193528679Sbrian    break;
193637210Sbrian
193736285Sbrian  case VAR_MTU:
193879163Sbrian    long_val = 0;	/* silence gcc */
193979163Sbrian    change = NULL;	/* silence gcc */
194078410Sbrian    switch(arg->argc - arg->argn) {
194178410Sbrian    case 1:
194279119Sbrian      if (argp[strspn(argp, "0123456789")] != '\0') {
194379119Sbrian        res = -1;
194479119Sbrian        break;
194579119Sbrian      }
194679119Sbrian      /*FALLTHRU*/
194778410Sbrian    case 0:
194878410Sbrian      long_val = atol(argp);
194978410Sbrian      change = &l->lcp.cfg.mtu;
195078410Sbrian      if (long_val > l->lcp.cfg.max_mtu) {
195178410Sbrian        log_Printf(LogWARN, "MTU %ld: too large - max set to %d\n", long_val,
195278410Sbrian                   l->lcp.cfg.max_mtu);
195379119Sbrian        res = 1;
195479119Sbrian        break;
195578410Sbrian      }
195678410Sbrian      break;
195778410Sbrian    case 2:
195879119Sbrian      if (strcasecmp(argp, "max") && strcasecmp(argp, "maximum")) {
195979119Sbrian        res = -1;
196079119Sbrian        break;
196179119Sbrian      }
196278410Sbrian      long_val = atol(arg->argv[arg->argn + 1]);
196378410Sbrian      change = &l->lcp.cfg.max_mtu;
196478410Sbrian      if (long_val > MAX_MTU) {
196578410Sbrian        log_Printf(LogWARN, "MTU %ld: too large - maximum is %d\n", long_val,
196678410Sbrian                   MAX_MTU);
196779119Sbrian        res = 1;
196879119Sbrian        break;
196978410Sbrian      }
197078410Sbrian      break;
197178410Sbrian    default:
197279119Sbrian      res = -1;
197379119Sbrian      break;
197478410Sbrian    }
197578410Sbrian
197679119Sbrian    if (res != 0)
197779119Sbrian      break;
197879119Sbrian
197937210Sbrian    if (long_val && long_val < MIN_MTU) {
198037210Sbrian      log_Printf(LogWARN, "MTU %ld: too small - min %d\n", long_val, MIN_MTU);
198179119Sbrian      res = 1;
198279119Sbrian      break;
198337210Sbrian    } else if (long_val > MAX_MTU) {
198437210Sbrian      log_Printf(LogWARN, "MTU %ld: too big - max %d\n", long_val, MAX_MTU);
198579119Sbrian      res = 1;
198679119Sbrian      break;
198737210Sbrian    } else
198878410Sbrian      *change = long_val;
198978410Sbrian    if (l->lcp.cfg.mtu > *change)
199078410Sbrian      l->lcp.cfg.mtu = *change;
199136285Sbrian    break;
199237210Sbrian
199336285Sbrian  case VAR_OPENMODE:
199436285Sbrian    if (strcasecmp(argp, "active") == 0)
199536285Sbrian      cx->physical->link.lcp.cfg.openmode = arg->argc > arg->argn+1 ?
199636285Sbrian        atoi(arg->argv[arg->argn+1]) : 1;
199736285Sbrian    else if (strcasecmp(argp, "passive") == 0)
199836285Sbrian      cx->physical->link.lcp.cfg.openmode = OPEN_PASSIVE;
199936285Sbrian    else {
200079119Sbrian      log_Printf(LogWARN, "%s: Invalid openmode\n", argp);
200179119Sbrian      res = 1;
200236285Sbrian    }
200336285Sbrian    break;
200437210Sbrian
200528679Sbrian  case VAR_PHONE:
200636285Sbrian    strncpy(cx->cfg.phone.list, argp, sizeof cx->cfg.phone.list - 1);
200736285Sbrian    cx->cfg.phone.list[sizeof cx->cfg.phone.list - 1] = '\0';
200838174Sbrian    cx->phone.alt = cx->phone.next = NULL;
200928679Sbrian    break;
201037210Sbrian
201128679Sbrian  case VAR_HANGUP:
201236285Sbrian    strncpy(cx->cfg.script.hangup, argp, sizeof cx->cfg.script.hangup - 1);
201336285Sbrian    cx->cfg.script.hangup[sizeof cx->cfg.script.hangup - 1] = '\0';
201428679Sbrian    break;
201537210Sbrian
201661534Sbrian  case VAR_IFQUEUE:
201761534Sbrian    long_val = atol(argp);
201861534Sbrian    arg->bundle->cfg.ifqueue = long_val < 0 ? 0 : long_val;
201961534Sbrian    break;
202061534Sbrian
202152488Sbrian  case VAR_LOGOUT:
202252488Sbrian    strncpy(cx->cfg.script.logout, argp, sizeof cx->cfg.script.logout - 1);
202352488Sbrian    cx->cfg.script.logout[sizeof cx->cfg.script.logout - 1] = '\0';
202452488Sbrian    break;
202552488Sbrian
202636285Sbrian  case VAR_IDLETIMEOUT:
202779119Sbrian    if (arg->argc > arg->argn+2) {
202879119Sbrian      log_Printf(LogWARN, "Too many idle timeout values\n");
202979119Sbrian      res = 1;
203079119Sbrian    } else if (arg->argc == arg->argn) {
203179119Sbrian      log_Printf(LogWARN, "Too few idle timeout values\n");
203279119Sbrian      res = 1;
203379119Sbrian    } else {
2034134789Sbrian      unsigned long timeout, min;
203549978Sbrian
2036134789Sbrian      timeout = strtoul(argp, NULL, 10);
2037134789Sbrian      min = arg->bundle->cfg.idle.min_timeout;
2038134789Sbrian      if (arg->argc == arg->argn + 2)
2039134789Sbrian	min = strtoul(arg->argv[arg->argn + 1], NULL, 10);
204049978Sbrian      bundle_SetIdleTimer(arg->bundle, timeout, min);
204149978Sbrian    }
204229549Sbrian    break;
2043132273Sbrian
2044132273Sbrian#ifndef NORADIUS
2045132273Sbrian  case VAR_RAD_ALIVE:
2046132273Sbrian    if (arg->argc > arg->argn + 2) {
2047132273Sbrian      log_Printf(LogWARN, "Too many RADIUS alive interval values\n");
2048132273Sbrian      res = 1;
2049132273Sbrian    } else if (arg->argc == arg->argn) {
2050132273Sbrian      log_Printf(LogWARN, "Too few RADIUS alive interval values\n");
2051132273Sbrian      res = 1;
2052132273Sbrian    } else {
2053132273Sbrian      arg->bundle->radius.alive.interval = atoi(argp);
2054132273Sbrian      if (arg->bundle->radius.alive.interval && !arg->bundle->radius.cfg.file) {
2055132273Sbrian        log_Printf(LogWARN, "rad_alive requires radius to be configured\n");
2056132273Sbrian	res = 1;
2057132273Sbrian      } else if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED) {
2058132273Sbrian	if (arg->bundle->radius.alive.interval)
2059132273Sbrian	  radius_StartTimer(arg->bundle);
2060132273Sbrian	else
2061132273Sbrian	  radius_StopTimer(&arg->bundle->radius);
2062132273Sbrian      }
2063132273Sbrian    }
2064132273Sbrian    break;
2065132273Sbrian#endif
2066132273Sbrian
206736285Sbrian  case VAR_LQRPERIOD:
206837210Sbrian    long_val = atol(argp);
206937210Sbrian    if (long_val < MIN_LQRPERIOD) {
207037210Sbrian      log_Printf(LogWARN, "%ld: Invalid lqr period - min %d\n",
207137210Sbrian                 long_val, MIN_LQRPERIOD);
207279119Sbrian      res = 1;
207336285Sbrian    } else
207437210Sbrian      l->lcp.cfg.lqrperiod = long_val;
207536285Sbrian    break;
207637210Sbrian
207736285Sbrian  case VAR_LCPRETRY:
207879119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
207979119Sbrian                   &cx->physical->link.lcp.cfg.fsm.timeout,
208079119Sbrian                   &cx->physical->link.lcp.cfg.fsm.maxreq,
208179119Sbrian                   &cx->physical->link.lcp.cfg.fsm.maxtrm, DEF_FSMTRIES);
208236285Sbrian    break;
208337210Sbrian
208436285Sbrian  case VAR_CHAPRETRY:
208579119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
208679119Sbrian                   &cx->chap.auth.cfg.fsm.timeout,
208779119Sbrian                   &cx->chap.auth.cfg.fsm.maxreq, NULL, DEF_FSMAUTHTRIES);
208836285Sbrian    break;
208937210Sbrian
209036285Sbrian  case VAR_PAPRETRY:
209179119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
209279119Sbrian                   &cx->pap.cfg.fsm.timeout, &cx->pap.cfg.fsm.maxreq,
209379119Sbrian                   NULL, DEF_FSMAUTHTRIES);
209436285Sbrian    break;
209537210Sbrian
209636285Sbrian  case VAR_CCPRETRY:
209779119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
209879119Sbrian                   &l->ccp.cfg.fsm.timeout, &l->ccp.cfg.fsm.maxreq,
209979119Sbrian                   &l->ccp.cfg.fsm.maxtrm, DEF_FSMTRIES);
210036285Sbrian    break;
210137210Sbrian
210236285Sbrian  case VAR_IPCPRETRY:
210379119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
210479119Sbrian                   &arg->bundle->ncp.ipcp.cfg.fsm.timeout,
210579119Sbrian                   &arg->bundle->ncp.ipcp.cfg.fsm.maxreq,
210679119Sbrian                   &arg->bundle->ncp.ipcp.cfg.fsm.maxtrm, DEF_FSMTRIES);
210736285Sbrian    break;
210837210Sbrian
2109102855Sbrian#ifndef NOINET6
2110102558Sbrian  case VAR_IPV6CPRETRY:
2111102558Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
2112102558Sbrian                   &arg->bundle->ncp.ipv6cp.cfg.fsm.timeout,
2113102558Sbrian                   &arg->bundle->ncp.ipv6cp.cfg.fsm.maxreq,
2114102558Sbrian                   &arg->bundle->ncp.ipv6cp.cfg.fsm.maxtrm, DEF_FSMTRIES);
2115102558Sbrian    break;
2116102855Sbrian#endif
2117102558Sbrian
211836285Sbrian  case VAR_NBNS:
211936285Sbrian  case VAR_DNS:
212058044Sbrian    if (param == VAR_DNS) {
212181634Sbrian      ipaddr = arg->bundle->ncp.ipcp.cfg.ns.dns;
212281634Sbrian      ipaddr[0].s_addr = ipaddr[1].s_addr = INADDR_NONE;
212358044Sbrian    } else {
212481634Sbrian      ipaddr = arg->bundle->ncp.ipcp.cfg.ns.nbns;
212581634Sbrian      ipaddr[0].s_addr = ipaddr[1].s_addr = INADDR_ANY;
212658044Sbrian    }
212736285Sbrian
212836285Sbrian    if (arg->argc > arg->argn) {
212981634Sbrian      ncpaddr_aton(ncpaddr, &arg->bundle->ncp, arg->argv[arg->argn]);
213081634Sbrian      if (!ncpaddr_getip4(ncpaddr, ipaddr))
213181634Sbrian        return -1;
213281634Sbrian      if (arg->argc > arg->argn+1) {
213381634Sbrian        ncpaddr_aton(ncpaddr + 1, &arg->bundle->ncp, arg->argv[arg->argn + 1]);
213481634Sbrian        if (!ncpaddr_getip4(ncpaddr + 1, ipaddr + 1))
213581634Sbrian          return -1;
213681634Sbrian      }
213736285Sbrian
213881634Sbrian      if (ipaddr[0].s_addr == INADDR_ANY) {
213981634Sbrian        ipaddr[0] = ipaddr[1];
214081634Sbrian        ipaddr[1].s_addr = INADDR_ANY;
214158044Sbrian      }
214281634Sbrian      if (ipaddr[0].s_addr == INADDR_NONE) {
214381634Sbrian        ipaddr[0] = ipaddr[1];
214481634Sbrian        ipaddr[1].s_addr = INADDR_NONE;
214558044Sbrian      }
214636285Sbrian    }
214736285Sbrian    break;
214838174Sbrian
214938174Sbrian  case VAR_CALLBACK:
215038174Sbrian    cx->cfg.callback.opmask = 0;
215138174Sbrian    for (dummyint = arg->argn; dummyint < arg->argc; dummyint++) {
215238174Sbrian      if (!strcasecmp(arg->argv[dummyint], "auth"))
215338174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_AUTH);
215438174Sbrian      else if (!strcasecmp(arg->argv[dummyint], "cbcp"))
215538174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_CBCP);
215638174Sbrian      else if (!strcasecmp(arg->argv[dummyint], "e.164")) {
215738174Sbrian        if (dummyint == arg->argc - 1)
215838174Sbrian          log_Printf(LogWARN, "No E.164 arg (E.164 ignored) !\n");
215938174Sbrian        else {
216038174Sbrian          cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_E164);
216138174Sbrian          strncpy(cx->cfg.callback.msg, arg->argv[++dummyint],
216238174Sbrian                  sizeof cx->cfg.callback.msg - 1);
216338174Sbrian          cx->cfg.callback.msg[sizeof cx->cfg.callback.msg - 1] = '\0';
216438174Sbrian        }
216538174Sbrian      } else if (!strcasecmp(arg->argv[dummyint], "none"))
216638174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_NONE);
216779119Sbrian      else {
216879119Sbrian        res = -1;
216979119Sbrian        break;
217079119Sbrian      }
217138174Sbrian    }
217238174Sbrian    if (cx->cfg.callback.opmask == CALLBACK_BIT(CALLBACK_NONE))
217338174Sbrian      cx->cfg.callback.opmask = 0;
217438174Sbrian    break;
217538174Sbrian
217638174Sbrian  case VAR_CBCP:
217738174Sbrian    cx->cfg.cbcp.delay = 0;
217838174Sbrian    *cx->cfg.cbcp.phone = '\0';
217938174Sbrian    cx->cfg.cbcp.fsmretry = DEF_FSMRETRY;
218038174Sbrian    if (arg->argc > arg->argn) {
218138174Sbrian      strncpy(cx->cfg.cbcp.phone, arg->argv[arg->argn],
218238174Sbrian              sizeof cx->cfg.cbcp.phone - 1);
218338174Sbrian      cx->cfg.cbcp.phone[sizeof cx->cfg.cbcp.phone - 1] = '\0';
218438174Sbrian      if (arg->argc > arg->argn + 1) {
218538174Sbrian        cx->cfg.cbcp.delay = atoi(arg->argv[arg->argn + 1]);
218638174Sbrian        if (arg->argc > arg->argn + 2) {
218738174Sbrian          long_val = atol(arg->argv[arg->argn + 2]);
218838174Sbrian          if (long_val < MIN_FSMRETRY)
218938174Sbrian            log_Printf(LogWARN, "%ld: Invalid CBCP FSM retry period - min %d\n",
219038174Sbrian                       long_val, MIN_FSMRETRY);
219138174Sbrian          else
219238174Sbrian            cx->cfg.cbcp.fsmretry = long_val;
219338174Sbrian        }
219438174Sbrian      }
219538174Sbrian    }
219638174Sbrian    break;
219738544Sbrian
219838544Sbrian  case VAR_CHOKED:
219938544Sbrian    arg->bundle->cfg.choked.timeout = atoi(argp);
220038544Sbrian    if (arg->bundle->cfg.choked.timeout <= 0)
220138544Sbrian      arg->bundle->cfg.choked.timeout = CHOKED_TIMEOUT;
220238544Sbrian    break;
220340665Sbrian
220440665Sbrian  case VAR_SENDPIPE:
220540665Sbrian    long_val = atol(argp);
220681634Sbrian    arg->bundle->ncp.cfg.sendpipe = long_val;
220740665Sbrian    break;
220840665Sbrian
220940665Sbrian  case VAR_RECVPIPE:
221040665Sbrian    long_val = atol(argp);
221181634Sbrian    arg->bundle->ncp.cfg.recvpipe = long_val;
221240665Sbrian    break;
221343313Sbrian
221443313Sbrian#ifndef NORADIUS
221543313Sbrian  case VAR_RADIUS:
221643313Sbrian    if (!*argp)
221743313Sbrian      *arg->bundle->radius.cfg.file = '\0';
221843313Sbrian    else if (access(argp, R_OK)) {
221943313Sbrian      log_Printf(LogWARN, "%s: %s\n", argp, strerror(errno));
222079119Sbrian      res = 1;
222179119Sbrian      break;
222243313Sbrian    } else {
222343313Sbrian      strncpy(arg->bundle->radius.cfg.file, argp,
222443313Sbrian              sizeof arg->bundle->radius.cfg.file - 1);
222543313Sbrian      arg->bundle->radius.cfg.file
222643313Sbrian        [sizeof arg->bundle->radius.cfg.file - 1] = '\0';
222743313Sbrian    }
222843313Sbrian    break;
222943313Sbrian#endif
223044073Sbrian
223144073Sbrian  case VAR_CD:
223244073Sbrian    if (*argp) {
223351699Sbrian      if (strcasecmp(argp, "off")) {
223451699Sbrian        long_val = atol(argp);
223551699Sbrian        if (long_val < 0)
223651699Sbrian          long_val = 0;
223751699Sbrian        cx->physical->cfg.cd.delay = long_val;
223851699Sbrian        cx->physical->cfg.cd.necessity = argp[strlen(argp)-1] == '!' ?
223951699Sbrian          CD_REQUIRED : CD_VARIABLE;
224051699Sbrian      } else
224151699Sbrian        cx->physical->cfg.cd.necessity = CD_NOTREQUIRED;
224244073Sbrian    } else {
224353733Sbrian      cx->physical->cfg.cd.delay = 0;
224453733Sbrian      cx->physical->cfg.cd.necessity = CD_DEFAULT;
224544073Sbrian    }
224644073Sbrian    break;
224736285Sbrian
224846686Sbrian  case VAR_PARITY:
224946686Sbrian    if (arg->argc == arg->argn + 1)
225079119Sbrian      res = physical_SetParity(arg->cx->physical, argp);
225146686Sbrian    else {
225279119Sbrian      log_Printf(LogWARN, "Parity value must be odd, even or none\n");
225379119Sbrian      res = 1;
225446686Sbrian    }
225546686Sbrian    break;
22566059Samurai
225746686Sbrian  case VAR_CRTSCTS:
225846686Sbrian    if (strcasecmp(argp, "on") == 0)
225936285Sbrian      physical_SetRtsCts(arg->cx->physical, 1);
226046686Sbrian    else if (strcasecmp(argp, "off") == 0)
226136285Sbrian      physical_SetRtsCts(arg->cx->physical, 0);
226246686Sbrian    else {
226379119Sbrian      log_Printf(LogWARN, "RTS/CTS value must be on or off\n");
226479119Sbrian      res = 1;
226546686Sbrian    }
226646686Sbrian    break;
226750867Sbrian
226850867Sbrian  case VAR_URGENTPORTS:
226951048Sbrian    if (arg->argn == arg->argc) {
227081634Sbrian      ncp_SetUrgentTOS(&arg->bundle->ncp);
227181634Sbrian      ncp_ClearUrgentTcpPorts(&arg->bundle->ncp);
227281634Sbrian      ncp_ClearUrgentUdpPorts(&arg->bundle->ncp);
227351048Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "udp")) {
227481634Sbrian      ncp_SetUrgentTOS(&arg->bundle->ncp);
227551048Sbrian      if (arg->argn == arg->argc - 1)
227681634Sbrian        ncp_ClearUrgentUdpPorts(&arg->bundle->ncp);
227751048Sbrian      else for (f = arg->argn + 1; f < arg->argc; f++)
227851048Sbrian        if (*arg->argv[f] == '+')
227981634Sbrian          ncp_AddUrgentUdpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1));
228051048Sbrian        else if (*arg->argv[f] == '-')
228181634Sbrian          ncp_RemoveUrgentUdpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1));
228251048Sbrian        else {
228351048Sbrian          if (f == arg->argn)
228481634Sbrian            ncp_ClearUrgentUdpPorts(&arg->bundle->ncp);
228581634Sbrian          ncp_AddUrgentUdpPort(&arg->bundle->ncp, atoi(arg->argv[f]));
228651048Sbrian        }
228761430Sbrian    } else if (arg->argn == arg->argc - 1 &&
228861430Sbrian               !strcasecmp(arg->argv[arg->argn], "none")) {
228981634Sbrian      ncp_ClearUrgentTcpPorts(&arg->bundle->ncp);
229081634Sbrian      ncp_ClearUrgentUdpPorts(&arg->bundle->ncp);
229181634Sbrian      ncp_ClearUrgentTOS(&arg->bundle->ncp);
229251048Sbrian    } else {
229381634Sbrian      ncp_SetUrgentTOS(&arg->bundle->ncp);
229451048Sbrian      first = arg->argn;
229551048Sbrian      if (!strcasecmp(arg->argv[first], "tcp") && ++first == arg->argc)
229681634Sbrian        ncp_ClearUrgentTcpPorts(&arg->bundle->ncp);
229751048Sbrian
229851048Sbrian      for (f = first; f < arg->argc; f++)
229951048Sbrian        if (*arg->argv[f] == '+')
230081634Sbrian          ncp_AddUrgentTcpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1));
230151048Sbrian        else if (*arg->argv[f] == '-')
230281634Sbrian          ncp_RemoveUrgentTcpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1));
230351048Sbrian        else {
230451048Sbrian          if (f == first)
230581634Sbrian            ncp_ClearUrgentTcpPorts(&arg->bundle->ncp);
230681634Sbrian          ncp_AddUrgentTcpPort(&arg->bundle->ncp, atoi(arg->argv[f]));
230751048Sbrian        }
230851048Sbrian    }
230950867Sbrian    break;
2310132818Sglebius
2311132818Sglebius  case VAR_PPPOE:
2312132818Sglebius    if (strcasecmp(argp, "3Com") == 0)
2313132818Sglebius      physical_SetPPPoEnonstandard(arg->cx->physical, 1);
2314132818Sglebius    else if (strcasecmp(argp, "standard") == 0)
2315132818Sglebius      physical_SetPPPoEnonstandard(arg->cx->physical, 0);
2316132818Sglebius    else {
2317132818Sglebius      log_Printf(LogWARN, "PPPoE standard value must be \"standard\" or \"3Com\"\n");
2318132818Sglebius      res = 1;
2319132818Sglebius    }
2320132818Sglebius    break;
2321132818Sglebius
2322169986Snovel#ifndef NORADIUS
2323169986Snovel  case VAR_PORT_ID:
2324169986Snovel    if (strcasecmp(argp, "default") == 0)
2325169986Snovel	    arg->bundle->radius.port_id_type = RPI_DEFAULT;
2326169986Snovel    else if (strcasecmp(argp, "pid") == 0)
2327169986Snovel	    arg->bundle->radius.port_id_type = RPI_PID;
2328169986Snovel    else if (strcasecmp(argp, "ifnum") == 0)
2329169986Snovel	    arg->bundle->radius.port_id_type = RPI_IFNUM;
2330169986Snovel    else if (strcasecmp(argp, "tunnum") == 0)
2331169986Snovel	    arg->bundle->radius.port_id_type = RPI_TUNNUM;
2332169986Snovel    else {
2333169986Snovel	   log_Printf(LogWARN,
2334169986Snovel		"RADIUS port id must be one of \"default\", \"pid\", \"ifnum\" or \"tunnum\"\n");
2335169986Snovel	   res = 1;
2336169986Snovel    }
2337169986Snovel
2338169986Snovel    if (arg->bundle->radius.port_id_type && !arg->bundle->radius.cfg.file) {
2339169986Snovel	    log_Printf(LogWARN, "rad_port_id requires radius to be configured\n");
2340169986Snovel	    res = 1;
2341169986Snovel    }
2342169986Snovel
2343169986Snovel    break;
2344169986Snovel#endif
234520812Sjkh  }
234646686Sbrian
234779119Sbrian  return res;
234820812Sjkh}
234920812Sjkh
235030715Sbrianstatic struct cmdtab const SetCommands[] = {
235136285Sbrian  {"accmap", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
235236285Sbrian  "accmap value", "set accmap hex-value", (const void *)VAR_ACCMAP},
235328679Sbrian  {"authkey", "key", SetVariable, LOCAL_AUTH,
235436285Sbrian  "authentication key", "set authkey|key key", (const void *)VAR_AUTHKEY},
235528679Sbrian  {"authname", NULL, SetVariable, LOCAL_AUTH,
235636285Sbrian  "authentication name", "set authname name", (const void *)VAR_AUTHNAME},
235736285Sbrian  {"autoload", NULL, SetVariable, LOCAL_AUTH,
235836285Sbrian  "auto link [de]activation", "set autoload maxtime maxload mintime minload",
235936285Sbrian  (const void *)VAR_AUTOLOAD},
236050867Sbrian  {"bandwidth", NULL, mp_SetDatalinkBandwidth, LOCAL_AUTH | LOCAL_CX,
2361134789Sbrian  "datalink bandwidth", "set bandwidth value", NULL},
236238174Sbrian  {"callback", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
236338174Sbrian  "callback control", "set callback [none|auth|cbcp|"
236438174Sbrian  "E.164 *|number[,number]...]...", (const void *)VAR_CALLBACK},
236538174Sbrian  {"cbcp", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
236698243Sbrian  "CBCP control", "set cbcp [*|phone[,phone...] [delay [timeout]]]",
236738174Sbrian  (const void *)VAR_CBCP},
236844305Sbrian  {"ccpretry", "ccpretries", SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
236944305Sbrian   "CCP retries", "set ccpretry value [attempts]", (const void *)VAR_CCPRETRY},
237044073Sbrian  {"cd", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "Carrier delay requirement",
237144073Sbrian   "set cd value[!]", (const void *)VAR_CD},
237244305Sbrian  {"chapretry", "chapretries", SetVariable, LOCAL_AUTH | LOCAL_CX,
237344305Sbrian   "CHAP retries", "set chapretry value [attempts]",
237444305Sbrian   (const void *)VAR_CHAPRETRY},
237538544Sbrian  {"choked", NULL, SetVariable, LOCAL_AUTH,
237638544Sbrian  "choked timeout", "set choked [secs]", (const void *)VAR_CHOKED},
237746686Sbrian  {"ctsrts", "crtscts", SetVariable, LOCAL_AUTH | LOCAL_CX,
237846686Sbrian   "Use hardware flow control", "set ctsrts [on|off]",
237946686Sbrian   (const char *)VAR_CRTSCTS},
238036285Sbrian  {"deflate", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
238136285Sbrian  "deflate window sizes", "set deflate out-winsize in-winsize",
238236285Sbrian  (const void *) VAR_WINSIZE},
238393418Sbrian#ifndef NODES
238467910Sbrian  {"mppe", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
238598243Sbrian  "MPPE key size and state", "set mppe [40|56|128|* [stateful|stateless|*]]",
238678411Sbrian  (const void *) VAR_MPPE},
238767910Sbrian#endif
238836285Sbrian  {"device", "line", SetVariable, LOCAL_AUTH | LOCAL_CX,
238946686Sbrian  "physical device name", "set device|line device-name[,device-name]",
239036285Sbrian  (const void *) VAR_DEVICE},
239136285Sbrian  {"dial", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
239236285Sbrian  "dialing script", "set dial chat-script", (const void *) VAR_DIAL},
239336285Sbrian  {"dns", NULL, SetVariable, LOCAL_AUTH, "Domain Name Server",
239436285Sbrian  "set dns pri-addr [sec-addr]", (const void *)VAR_DNS},
239536285Sbrian  {"enddisc", NULL, mp_SetEnddisc, LOCAL_AUTH,
2396134789Sbrian  "Endpoint Discriminator", "set enddisc [IP|magic|label|psn value]", NULL},
239736285Sbrian  {"escape", NULL, SetEscape, LOCAL_AUTH | LOCAL_CX,
2398134789Sbrian  "escape characters", "set escape hex-digit ...", NULL},
239936285Sbrian  {"filter", NULL, filter_Set, LOCAL_AUTH,
240036285Sbrian  "packet filters", "set filter alive|dial|in|out rule-no permit|deny "
240181634Sbrian  "[src_addr[/width]] [dst_addr[/width]] [proto "
2402134789Sbrian  "[src [lt|eq|gt port]] [dst [lt|eq|gt port]] [estab] [syn] [finrst]]", NULL},
240336285Sbrian  {"hangup", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
240436285Sbrian  "hangup script", "set hangup chat-script", (const void *) VAR_HANGUP},
240536285Sbrian  {"ifaddr", NULL, SetInterfaceAddr, LOCAL_AUTH, "destination address",
2406134789Sbrian  "set ifaddr [src-addr [dst-addr [netmask [trg-addr]]]]", NULL},
240761534Sbrian  {"ifqueue", NULL, SetVariable, LOCAL_AUTH, "interface queue",
240861534Sbrian  "set ifqueue packets", (const void *)VAR_IFQUEUE},
240944305Sbrian  {"ipcpretry", "ipcpretries", SetVariable, LOCAL_AUTH, "IPCP retries",
241044305Sbrian   "set ipcpretry value [attempts]", (const void *)VAR_IPCPRETRY},
2411102558Sbrian  {"ipv6cpretry", "ipv6cpretries", SetVariable, LOCAL_AUTH, "IPV6CP retries",
2412102558Sbrian   "set ipv6cpretry value [attempts]", (const void *)VAR_IPV6CPRETRY},
241344305Sbrian  {"lcpretry", "lcpretries", SetVariable, LOCAL_AUTH | LOCAL_CX, "LCP retries",
241444305Sbrian   "set lcpretry value [attempts]", (const void *)VAR_LCPRETRY},
241536712Sbrian  {"log", NULL, log_SetLevel, LOCAL_AUTH, "log level",
241667916Sbrian  "set log [local] [+|-]all|async|cbcp|ccp|chat|command|connect|debug|dns|hdlc|"
2417134789Sbrian  "id0|ipcp|lcp|lqm|phase|physical|radius|sync|tcp/ip|timer|tun...", NULL},
241836285Sbrian  {"login", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
241936285Sbrian  "login script", "set login chat-script", (const void *) VAR_LOGIN},
242052488Sbrian  {"logout", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
242152488Sbrian  "logout script", "set logout chat-script", (const void *) VAR_LOGOUT},
2422138799Sbrian  {"lqrperiod", "echoperiod", SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
2423138799Sbrian  "LQR period", "set lqr/echo period value", (const void *)VAR_LQRPERIOD},
242436285Sbrian  {"mode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "mode value",
242536285Sbrian  "set mode interactive|auto|ddial|background", (const void *)VAR_MODE},
242636285Sbrian  {"mrru", NULL, SetVariable, LOCAL_AUTH, "MRRU value",
242736285Sbrian  "set mrru value", (const void *)VAR_MRRU},
242896038Sbrian  {"mru", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
242978410Sbrian  "MRU value", "set mru [max[imum]] [value]", (const void *)VAR_MRU},
243078410Sbrian  {"mtu", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
243178410Sbrian  "interface MTU value", "set mtu [max[imum]] [value]", (const void *)VAR_MTU},
243236285Sbrian  {"nbns", NULL, SetVariable, LOCAL_AUTH, "NetBIOS Name Server",
243336285Sbrian  "set nbns pri-addr [sec-addr]", (const void *)VAR_NBNS},
243436285Sbrian  {"openmode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "open mode",
243536285Sbrian  "set openmode active|passive [secs]", (const void *)VAR_OPENMODE},
243644305Sbrian  {"papretry", "papretries", SetVariable, LOCAL_AUTH | LOCAL_CX, "PAP retries",
243744305Sbrian   "set papretry value [attempts]", (const void *)VAR_PAPRETRY},
243846686Sbrian  {"parity", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "serial parity",
243946686Sbrian   "set parity [odd|even|none]", (const void *)VAR_PARITY},
244036285Sbrian  {"phone", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "telephone number(s)",
244136285Sbrian  "set phone phone1[:phone2[...]]", (const void *)VAR_PHONE},
244240679Sbrian  {"proctitle", "title", SetProcTitle, LOCAL_AUTH,
2443134789Sbrian  "Process title", "set proctitle [value]", NULL},
244443313Sbrian#ifndef NORADIUS
244543313Sbrian  {"radius", NULL, SetVariable, LOCAL_AUTH,
244643313Sbrian  "RADIUS Config", "set radius cfgfile", (const void *)VAR_RADIUS},
2447132273Sbrian  {"rad_alive", NULL, SetVariable, LOCAL_AUTH,
2448132273Sbrian  "Raduis alive interval", "set rad_alive value",
2449169986Snovel  (const void *)VAR_RAD_ALIVE},
2450169986Snovel  {"rad_port_id", NULL, SetVariable, LOCAL_AUTH,
2451169986Snovel  "NAS-Port-Id", "set rad_port_id [default|pid|ifnum|tunnum]", (const void *)VAR_PORT_ID},
245243313Sbrian#endif
245336285Sbrian  {"reconnect", NULL, datalink_SetReconnect, LOCAL_AUTH | LOCAL_CX,
2454134789Sbrian  "Reconnect timeout", "set reconnect value ntries", NULL},
245540665Sbrian  {"recvpipe", NULL, SetVariable, LOCAL_AUTH,
245640665Sbrian  "RECVPIPE value", "set recvpipe value", (const void *)VAR_RECVPIPE},
245736285Sbrian  {"redial", NULL, datalink_SetRedial, LOCAL_AUTH | LOCAL_CX,
2458134789Sbrian  "Redial timeout", "set redial secs[+inc[-incmax]][.next] [attempts]", NULL},
245940665Sbrian  {"sendpipe", NULL, SetVariable, LOCAL_AUTH,
246040665Sbrian  "SENDPIPE value", "set sendpipe value", (const void *)VAR_SENDPIPE},
246171657Sbrian  {"server", "socket", SetServer, LOCAL_AUTH, "diagnostic port",
2462134789Sbrian  "set server|socket TcpPort|LocalName|none|open|closed [password [mask]]",
2463134789Sbrian  NULL},
246436285Sbrian  {"speed", NULL, SetModemSpeed, LOCAL_AUTH | LOCAL_CX,
2465134789Sbrian  "physical speed", "set speed value|sync", NULL},
246636285Sbrian  {"stopped", NULL, SetStoppedTimeout, LOCAL_AUTH | LOCAL_CX,
2467134789Sbrian  "STOPPED timeouts", "set stopped [LCPseconds [CCPseconds]]", NULL},
246836285Sbrian  {"timeout", NULL, SetVariable, LOCAL_AUTH, "Idle timeout",
246936285Sbrian  "set timeout idletime", (const void *)VAR_IDLETIMEOUT},
247051048Sbrian  {"urgent", NULL, SetVariable, LOCAL_AUTH, "urgent ports",
247151048Sbrian  "set urgent [tcp|udp] [+|-]port...", (const void *)VAR_URGENTPORTS},
247236285Sbrian  {"vj", NULL, ipcp_vjset, LOCAL_AUTH,
2473134789Sbrian  "vj values", "set vj slots|slotcomp [value]", NULL},
247428679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
247531343Sbrian  "Display this message", "set help|? [command]", SetCommands},
2476132818Sglebius  {"pppoe", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
2477132818Sglebius   "Connect using standard/3Com mode", "set pppoe [standard|3Com]",
2478132818Sglebius   (const char *)VAR_PPPOE},
2479134789Sbrian  {NULL, NULL, NULL, 0, NULL, NULL, NULL},
24806059Samurai};
24816059Samurai
24826059Samuraistatic int
248331343SbrianSetCommand(struct cmdargs const *arg)
24846059Samurai{
248536285Sbrian  if (arg->argc > arg->argn)
248636285Sbrian    FindExec(arg->bundle, SetCommands, arg->argc, arg->argn, arg->argv,
248736285Sbrian             arg->prompt, arg->cx);
248836285Sbrian  else if (arg->prompt)
248936285Sbrian    prompt_Printf(arg->prompt, "Use `set ?' to get a list or `set ? <var>' for"
249058044Sbrian	          " syntax help.\n");
24916059Samurai  else
249236285Sbrian    log_Printf(LogWARN, "set command must have arguments\n");
249326516Sbrian
249426516Sbrian  return 0;
24956059Samurai}
24966059Samurai
24976059Samuraistatic int
249831343SbrianAddCommand(struct cmdargs const *arg)
24996059Samurai{
250081634Sbrian  struct ncpaddr gw;
250181634Sbrian  struct ncprange dest;
250281634Sbrian  struct in_addr host;
2503112673Sume#ifndef NOINET6
2504112673Sume  struct in6_addr host6;
2505112673Sume#endif
250681634Sbrian  int dest_default, gw_arg, addrs;
25076059Samurai
250836285Sbrian  if (arg->argc != arg->argn+3 && arg->argc != arg->argn+2)
250931598Sbrian    return -1;
251031598Sbrian
251136285Sbrian  addrs = 0;
251281634Sbrian  dest_default = 0;
251381634Sbrian  if (arg->argc == arg->argn + 2) {
251436285Sbrian    if (!strcasecmp(arg->argv[arg->argn], "default"))
251581634Sbrian      dest_default = 1;
251631598Sbrian    else {
251781634Sbrian      if (!ncprange_aton(&dest, &arg->bundle->ncp, arg->argv[arg->argn]))
251836285Sbrian        return -1;
251936285Sbrian      if (!strncasecmp(arg->argv[arg->argn], "MYADDR", 6))
252036285Sbrian        addrs = ROUTE_DSTMYADDR;
252181634Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "MYADDR6", 7))
252281634Sbrian        addrs = ROUTE_DSTMYADDR6;
252336285Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "HISADDR", 7))
252436285Sbrian        addrs = ROUTE_DSTHISADDR;
252581634Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "HISADDR6", 8))
252681634Sbrian        addrs = ROUTE_DSTHISADDR6;
252758044Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "DNS0", 4))
252858044Sbrian        addrs = ROUTE_DSTDNS0;
252958044Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "DNS1", 4))
253058044Sbrian        addrs = ROUTE_DSTDNS1;
253131598Sbrian    }
253281634Sbrian    gw_arg = 1;
253334536Sbrian  } else {
253436285Sbrian    if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
253536285Sbrian      addrs = ROUTE_DSTMYADDR;
253681634Sbrian      host = arg->bundle->ncp.ipcp.my_ip;
253736285Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
253836285Sbrian      addrs = ROUTE_DSTHISADDR;
253981634Sbrian      host = arg->bundle->ncp.ipcp.peer_ip;
254058044Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "DNS0") == 0) {
254158044Sbrian      addrs = ROUTE_DSTDNS0;
254281634Sbrian      host = arg->bundle->ncp.ipcp.ns.dns[0];
254358044Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "DNS1") == 0) {
254458044Sbrian      addrs = ROUTE_DSTDNS1;
254581634Sbrian      host = arg->bundle->ncp.ipcp.ns.dns[1];
254665263Sbrian    } else {
254781634Sbrian      host = GetIpAddr(arg->argv[arg->argn]);
254881634Sbrian      if (host.s_addr == INADDR_NONE) {
254965263Sbrian        log_Printf(LogWARN, "%s: Invalid destination address\n",
255065263Sbrian                   arg->argv[arg->argn]);
255165263Sbrian        return -1;
255265263Sbrian      }
255365263Sbrian    }
255481634Sbrian    ncprange_setip4(&dest, host, GetIpAddr(arg->argv[arg->argn + 1]));
255581634Sbrian    gw_arg = 2;
25566059Samurai  }
255736285Sbrian
255881634Sbrian  if (strcasecmp(arg->argv[arg->argn + gw_arg], "HISADDR") == 0) {
255981634Sbrian    ncpaddr_setip4(&gw, arg->bundle->ncp.ipcp.peer_ip);
256036285Sbrian    addrs |= ROUTE_GWHISADDR;
256181634Sbrian#ifndef NOINET6
256281897Sbrian  } else if (strcasecmp(arg->argv[arg->argn + gw_arg], "HISADDR6") == 0) {
2563112673Sume    if (!ncpaddr_getip6(&arg->bundle->ncp.ipv6cp.hisaddr, &host6))
2564112673Sume      memset(&host6, '\0', sizeof host6);
2565112673Sume    ncpaddr_setip6(&gw, &host6);
256681634Sbrian    addrs |= ROUTE_GWHISADDR6;
256781634Sbrian#endif
256865263Sbrian  } else {
256981634Sbrian    if (!ncpaddr_aton(&gw, &arg->bundle->ncp, arg->argv[arg->argn + gw_arg])) {
257065263Sbrian      log_Printf(LogWARN, "%s: Invalid gateway address\n",
257181634Sbrian                 arg->argv[arg->argn + gw_arg]);
257265263Sbrian      return -1;
257365263Sbrian    }
257465263Sbrian  }
257536285Sbrian
257681634Sbrian  if (dest_default)
257781634Sbrian    ncprange_setdefault(&dest, ncpaddr_family(&gw));
257881634Sbrian
257981634Sbrian  if (rt_Set(arg->bundle, RTM_ADD, &dest, &gw, arg->cmd->args ? 1 : 0,
258081634Sbrian             ((addrs & ROUTE_GWHISADDR) || (addrs & ROUTE_GWHISADDR6)) ? 1 : 0)
258143313Sbrian      && addrs != ROUTE_STATIC)
258281634Sbrian    route_Add(&arg->bundle->ncp.route, addrs, &dest, &gw);
258336285Sbrian
258431598Sbrian  return 0;
25856059Samurai}
25866059Samurai
25876059Samuraistatic int
258831343SbrianDeleteCommand(struct cmdargs const *arg)
25896059Samurai{
259081634Sbrian  struct ncprange dest;
259136285Sbrian  int addrs;
25926059Samurai
259336285Sbrian  if (arg->argc == arg->argn+1) {
259436285Sbrian    if(strcasecmp(arg->argv[arg->argn], "all") == 0) {
259536285Sbrian      route_IfDelete(arg->bundle, 0);
259681634Sbrian      route_DeleteAll(&arg->bundle->ncp.route);
259736285Sbrian    } else {
259836285Sbrian      addrs = 0;
259936285Sbrian      if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
260081634Sbrian        ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.my_ip);
260136285Sbrian        addrs = ROUTE_DSTMYADDR;
260281634Sbrian#ifndef NOINET6
260381897Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "MYADDR6") == 0) {
260481634Sbrian        ncprange_sethost(&dest, &arg->bundle->ncp.ipv6cp.myaddr);
260581634Sbrian        addrs = ROUTE_DSTMYADDR6;
260681634Sbrian#endif
260736285Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
260881634Sbrian        ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.peer_ip);
260936285Sbrian        addrs = ROUTE_DSTHISADDR;
261081634Sbrian#ifndef NOINET6
261181897Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "HISADDR6") == 0) {
261281634Sbrian        ncprange_sethost(&dest, &arg->bundle->ncp.ipv6cp.hisaddr);
261381634Sbrian        addrs = ROUTE_DSTHISADDR6;
261481634Sbrian#endif
261558044Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "DNS0") == 0) {
261681634Sbrian        ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.ns.dns[0]);
261758044Sbrian        addrs = ROUTE_DSTDNS0;
261858044Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "DNS1") == 0) {
261981634Sbrian        ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.ns.dns[1]);
262058044Sbrian        addrs = ROUTE_DSTDNS1;
262136285Sbrian      } else {
262281634Sbrian        ncprange_aton(&dest, &arg->bundle->ncp, arg->argv[arg->argn]);
262336285Sbrian        addrs = ROUTE_STATIC;
262436285Sbrian      }
262581634Sbrian      rt_Set(arg->bundle, RTM_DELETE, &dest, NULL, arg->cmd->args ? 1 : 0, 0);
262681634Sbrian      route_Delete(&arg->bundle->ncp.route, addrs, &dest);
262731598Sbrian    }
262834536Sbrian  } else
262926516Sbrian    return -1;
263026516Sbrian
263126516Sbrian  return 0;
26326059Samurai}
26336059Samurai
263450059Sbrian#ifndef NONAT
263526031Sbrianstatic int
263658867SbrianNatEnable(struct cmdargs const *arg)
263726031Sbrian{
263836285Sbrian  if (arg->argc == arg->argn+1) {
263936285Sbrian    if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
264050059Sbrian      if (!arg->bundle->NatEnabled) {
264146686Sbrian        if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED)
2642177100Spiso          LibAliasSetAddress(la, arg->bundle->ncp.ipcp.my_ip);
264350059Sbrian        arg->bundle->NatEnabled = 1;
264446686Sbrian      }
264537191Sbrian      return 0;
264636285Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "no") == 0) {
264750059Sbrian      arg->bundle->NatEnabled = 0;
2648138198Sbrian      opt_disable(arg->bundle, OPT_IFACEALIAS);
264940561Sbrian      /* Don't iface_Clear() - there may be manually configured addresses */
265026516Sbrian      return 0;
265126142Sbrian    }
265235449Sbrian  }
265336285Sbrian
265426516Sbrian  return -1;
265526031Sbrian}
265626031Sbrian
265726031Sbrian
265826031Sbrianstatic int
265958867SbrianNatOption(struct cmdargs const *arg)
266026031Sbrian{
266138559Sbrian  long param = (long)arg->cmd->args;
266238559Sbrian
266336285Sbrian  if (arg->argc == arg->argn+1) {
266436285Sbrian    if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
266550059Sbrian      if (arg->bundle->NatEnabled) {
2666177100Spiso	LibAliasSetMode(la, param, param);
266728679Sbrian	return 0;
266828679Sbrian      }
266950059Sbrian      log_Printf(LogWARN, "nat not enabled\n");
267036285Sbrian    } else if (strcmp(arg->argv[arg->argn], "no") == 0) {
267150059Sbrian      if (arg->bundle->NatEnabled) {
2672177100Spiso	LibAliasSetMode(la, 0, param);
267328679Sbrian	return 0;
267428679Sbrian      }
267550059Sbrian      log_Printf(LogWARN, "nat not enabled\n");
267628679Sbrian    }
267735449Sbrian  }
267828679Sbrian  return -1;
267926031Sbrian}
268050059Sbrian#endif /* #ifndef NONAT */
268131121Sbrian
268231121Sbrianstatic int
268336285SbrianLinkCommand(struct cmdargs const *arg)
268436285Sbrian{
268536285Sbrian  if (arg->argc > arg->argn+1) {
268636285Sbrian    char namelist[LINE_LEN];
268736285Sbrian    struct datalink *cx;
268836285Sbrian    char *name;
268936285Sbrian    int result = 0;
269036285Sbrian
269136285Sbrian    if (!strcmp(arg->argv[arg->argn], "*")) {
269236285Sbrian      struct datalink *dl;
269336285Sbrian
269436285Sbrian      cx = arg->bundle->links;
269536285Sbrian      while (cx) {
269636285Sbrian        /* Watch it, the command could be a ``remove'' */
269736285Sbrian        dl = cx->next;
269836285Sbrian        FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
269936285Sbrian                 arg->prompt, cx);
270036285Sbrian        for (cx = arg->bundle->links; cx; cx = cx->next)
270136285Sbrian          if (cx == dl)
270236285Sbrian            break;		/* Pointer's still valid ! */
270336285Sbrian      }
270436285Sbrian    } else {
270536285Sbrian      strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
270636285Sbrian      namelist[sizeof namelist - 1] = '\0';
270736285Sbrian      for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
270836285Sbrian        if (!bundle2datalink(arg->bundle, name)) {
270936285Sbrian          log_Printf(LogWARN, "link: %s: Invalid link name\n", name);
271036285Sbrian          return 1;
271136285Sbrian        }
271236285Sbrian
271336285Sbrian      strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
271436285Sbrian      namelist[sizeof namelist - 1] = '\0';
271536285Sbrian      for(name = strtok(namelist, ", "); name; name = strtok(NULL,", ")) {
271636285Sbrian        cx = bundle2datalink(arg->bundle, name);
271736285Sbrian        if (cx)
271836285Sbrian          FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
271936285Sbrian                   arg->prompt, cx);
272036285Sbrian        else {
272136285Sbrian          log_Printf(LogWARN, "link: %s: Invalidated link name !\n", name);
272236285Sbrian          result++;
272336285Sbrian        }
272436285Sbrian      }
272536285Sbrian    }
272636285Sbrian    return result;
272736285Sbrian  }
272836285Sbrian
272995258Sdes  log_Printf(LogWARN, "usage: %s\n", arg->cmd->syntax);
273036285Sbrian  return 2;
273136285Sbrian}
273236285Sbrian
273336285Sbrianstruct link *
273436285Sbriancommand_ChooseLink(struct cmdargs const *arg)
273536285Sbrian{
273636285Sbrian  if (arg->cx)
273736285Sbrian    return &arg->cx->physical->link;
273837210Sbrian  else if (!arg->bundle->ncp.mp.cfg.mrru) {
273936285Sbrian    struct datalink *dl = bundle2datalink(arg->bundle, NULL);
274037210Sbrian    if (dl)
274137210Sbrian      return &dl->physical->link;
274236285Sbrian  }
274337210Sbrian  return &arg->bundle->ncp.mp.link;
274436285Sbrian}
274536285Sbrian
274636285Sbrianstatic const char *
274736285Sbrianident_cmd(const char *cmd, unsigned *keep, unsigned *add)
274836285Sbrian{
274936285Sbrian  const char *result;
275036285Sbrian
275136285Sbrian  switch (*cmd) {
275236285Sbrian    case 'A':
275336285Sbrian    case 'a':
275436285Sbrian      result = "accept";
275536285Sbrian      *keep = NEG_MYMASK;
275636285Sbrian      *add = NEG_ACCEPTED;
275736285Sbrian      break;
275836285Sbrian    case 'D':
275936285Sbrian    case 'd':
276036285Sbrian      switch (cmd[1]) {
276136285Sbrian        case 'E':
276236285Sbrian        case 'e':
276336285Sbrian          result = "deny";
276436285Sbrian          *keep = NEG_MYMASK;
276536285Sbrian          *add = 0;
276636285Sbrian          break;
276736285Sbrian        case 'I':
276836285Sbrian        case 'i':
276936285Sbrian          result = "disable";
277036285Sbrian          *keep = NEG_HISMASK;
277136285Sbrian          *add = 0;
277236285Sbrian          break;
277336285Sbrian        default:
277436285Sbrian          return NULL;
277536285Sbrian      }
277636285Sbrian      break;
277736285Sbrian    case 'E':
277836285Sbrian    case 'e':
277936285Sbrian      result = "enable";
278036285Sbrian      *keep = NEG_HISMASK;
278136285Sbrian      *add = NEG_ENABLED;
278236285Sbrian      break;
278336285Sbrian    default:
278436285Sbrian      return NULL;
278536285Sbrian  }
278636285Sbrian
278736285Sbrian  return result;
278836285Sbrian}
278936285Sbrian
279036285Sbrianstatic int
279136285SbrianOptSet(struct cmdargs const *arg)
279236285Sbrian{
2793138198Sbrian  int opt = (int)(long)arg->cmd->args;
2794138198Sbrian  unsigned keep;			/* Keep this opt */
2795138198Sbrian  unsigned add;				/* Add this opt */
279636285Sbrian
279781697Sbrian  if (ident_cmd(arg->argv[arg->argn - 2], &keep, &add) == NULL)
279836285Sbrian    return 1;
279936285Sbrian
280081885Sbrian#ifndef NOINET6
2801138198Sbrian  if (add == NEG_ENABLED && opt == OPT_IPV6CP && !probe.ipv6_available) {
280281697Sbrian    log_Printf(LogWARN, "IPv6 is not available on this machine\n");
280381697Sbrian    return 1;
280481697Sbrian  }
280581885Sbrian#endif
2806138198Sbrian  if (!add && ((opt == OPT_NAS_IP_ADDRESS &&
2807138198Sbrian                !Enabled(arg->bundle, OPT_NAS_IDENTIFIER)) ||
2808138198Sbrian               (opt == OPT_NAS_IDENTIFIER &&
2809138198Sbrian                !Enabled(arg->bundle, OPT_NAS_IP_ADDRESS)))) {
2810138198Sbrian    log_Printf(LogWARN,
2811138198Sbrian               "Cannot disable both NAS-IP-Address and NAS-Identifier\n");
2812138198Sbrian    return 1;
2813138198Sbrian  }
281481697Sbrian
281536285Sbrian  if (add)
2816138198Sbrian    opt_enable(arg->bundle, opt);
281736285Sbrian  else
2818138198Sbrian    opt_disable(arg->bundle, opt);
281981697Sbrian
282036285Sbrian  return 0;
282136285Sbrian}
282236285Sbrian
282336285Sbrianstatic int
282440561SbrianIfaceAliasOptSet(struct cmdargs const *arg)
282540561Sbrian{
2826138198Sbrian  unsigned long long save = arg->bundle->cfg.optmask;
282740561Sbrian  int result = OptSet(arg);
282840561Sbrian
282940561Sbrian  if (result == 0)
283050059Sbrian    if (Enabled(arg->bundle, OPT_IFACEALIAS) && !arg->bundle->NatEnabled) {
2831138198Sbrian      arg->bundle->cfg.optmask = save;
283250059Sbrian      log_Printf(LogWARN, "Cannot enable iface-alias without NAT\n");
283340561Sbrian      result = 2;
283440561Sbrian    }
283540561Sbrian
283640561Sbrian  return result;
283740561Sbrian}
283840561Sbrian
283940561Sbrianstatic int
284036285SbrianNegotiateSet(struct cmdargs const *arg)
284136285Sbrian{
284237210Sbrian  long param = (long)arg->cmd->args;
284336285Sbrian  struct link *l = command_ChooseLink(arg);	/* LOCAL_CX_OPT uses this */
284436285Sbrian  struct datalink *cx = arg->cx;	/* LOCAL_CX uses this */
284536285Sbrian  const char *cmd;
284636285Sbrian  unsigned keep;			/* Keep these bits */
284736285Sbrian  unsigned add;				/* Add these bits */
284836285Sbrian
284936285Sbrian  if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL)
285036285Sbrian    return 1;
285136285Sbrian
285236285Sbrian  if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
285336285Sbrian    log_Printf(LogWARN, "%s %s: No context (use the `link' command)\n",
285436285Sbrian              cmd, arg->cmd->name);
285536285Sbrian    return 2;
285636285Sbrian  } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
285736285Sbrian    log_Printf(LogWARN, "%s %s: Redundant context (%s) ignored\n",
285836285Sbrian              cmd, arg->cmd->name, cx->name);
285936285Sbrian    cx = NULL;
286036285Sbrian  }
286136285Sbrian
286236285Sbrian  switch (param) {
286336285Sbrian    case NEG_ACFCOMP:
286436285Sbrian      cx->physical->link.lcp.cfg.acfcomp &= keep;
286536285Sbrian      cx->physical->link.lcp.cfg.acfcomp |= add;
286636285Sbrian      break;
286744106Sbrian    case NEG_CHAP05:
286844106Sbrian      cx->physical->link.lcp.cfg.chap05 &= keep;
286944106Sbrian      cx->physical->link.lcp.cfg.chap05 |= add;
287036285Sbrian      break;
287193418Sbrian#ifndef NODES
287244106Sbrian    case NEG_CHAP80:
287344106Sbrian      cx->physical->link.lcp.cfg.chap80nt &= keep;
287444106Sbrian      cx->physical->link.lcp.cfg.chap80nt |= add;
287544106Sbrian      break;
287644106Sbrian    case NEG_CHAP80LM:
287744106Sbrian      cx->physical->link.lcp.cfg.chap80lm &= keep;
287844106Sbrian      cx->physical->link.lcp.cfg.chap80lm |= add;
287944106Sbrian      break;
288067910Sbrian    case NEG_CHAP81:
288167910Sbrian      cx->physical->link.lcp.cfg.chap81 &= keep;
288267910Sbrian      cx->physical->link.lcp.cfg.chap81 |= add;
288367910Sbrian      break;
288467910Sbrian    case NEG_MPPE:
288567910Sbrian      l->ccp.cfg.neg[CCP_NEG_MPPE] &= keep;
288667910Sbrian      l->ccp.cfg.neg[CCP_NEG_MPPE] |= add;
288767910Sbrian      break;
288844106Sbrian#endif
288936285Sbrian    case NEG_DEFLATE:
289036285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE] &= keep;
289136285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE] |= add;
289236285Sbrian      break;
289336285Sbrian    case NEG_DNS:
289436285Sbrian      arg->bundle->ncp.ipcp.cfg.ns.dns_neg &= keep;
289536285Sbrian      arg->bundle->ncp.ipcp.cfg.ns.dns_neg |= add;
289636285Sbrian      break;
2897138799Sbrian    case NEG_ECHO:	/* probably misplaced in this function ! */
2898138799Sbrian      if (cx->physical->link.lcp.cfg.echo && !add) {
2899138799Sbrian        cx->physical->link.lcp.cfg.echo = 0;
2900138799Sbrian        cx->physical->hdlc.lqm.method &= ~LQM_ECHO;
2901138799Sbrian        if (cx->physical->hdlc.lqm.method & LQM_ECHO &&
2902138799Sbrian            !cx->physical->link.lcp.want_lqrperiod &&
2903138799Sbrian            cx->physical->hdlc.lqm.timer.load) {
2904138799Sbrian          cx->physical->hdlc.lqm.timer.load = 0;
2905138799Sbrian          lqr_StopTimer(cx->physical);
2906138799Sbrian        }
2907138799Sbrian      } else if (!cx->physical->link.lcp.cfg.echo && add) {
2908138799Sbrian        cx->physical->link.lcp.cfg.echo = 1;
2909138799Sbrian        cx->physical->hdlc.lqm.method |= LQM_ECHO;
2910138799Sbrian        cx->physical->hdlc.lqm.timer.load =
2911138799Sbrian	    cx->physical->link.lcp.cfg.lqrperiod * SECTICKS;
2912138799Sbrian        if (cx->physical->link.lcp.fsm.state == ST_OPENED)
2913138799Sbrian          (*cx->physical->hdlc.lqm.timer.func)(&cx->physical->link.lcp);
2914138799Sbrian      }
2915138799Sbrian      break;
291647858Sbrian    case NEG_ENDDISC:
291747858Sbrian      arg->bundle->ncp.mp.cfg.negenddisc &= keep;
291847858Sbrian      arg->bundle->ncp.mp.cfg.negenddisc |= add;
291947858Sbrian      break;
292036285Sbrian    case NEG_LQR:
292136285Sbrian      cx->physical->link.lcp.cfg.lqr &= keep;
292236285Sbrian      cx->physical->link.lcp.cfg.lqr |= add;
292336285Sbrian      break;
292436285Sbrian    case NEG_PAP:
292536285Sbrian      cx->physical->link.lcp.cfg.pap &= keep;
292636285Sbrian      cx->physical->link.lcp.cfg.pap |= add;
292736285Sbrian      break;
292836285Sbrian    case NEG_PPPDDEFLATE:
292936285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE24] &= keep;
293036285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE24] |= add;
293136285Sbrian      break;
293236285Sbrian    case NEG_PRED1:
293336285Sbrian      l->ccp.cfg.neg[CCP_NEG_PRED1] &= keep;
293436285Sbrian      l->ccp.cfg.neg[CCP_NEG_PRED1] |= add;
293536285Sbrian      break;
293636285Sbrian    case NEG_PROTOCOMP:
293736285Sbrian      cx->physical->link.lcp.cfg.protocomp &= keep;
293836285Sbrian      cx->physical->link.lcp.cfg.protocomp |= add;
293936285Sbrian      break;
294036285Sbrian    case NEG_SHORTSEQ:
294140622Sbrian      switch (bundle_Phase(arg->bundle)) {
294240622Sbrian        case PHASE_DEAD:
294340622Sbrian          break;
294440622Sbrian        case PHASE_ESTABLISH:
294540622Sbrian          /* Make sure none of our links are DATALINK_LCP or greater */
294640622Sbrian          if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) {
2947228990Suqs            log_Printf(LogWARN, "shortseq: Only changeable before"
294840622Sbrian                       " LCP negotiations\n");
294940622Sbrian            return 1;
295040622Sbrian          }
295140622Sbrian          break;
295240622Sbrian        default:
2953228990Suqs          log_Printf(LogWARN, "shortseq: Only changeable at phase"
295440622Sbrian                     " DEAD/ESTABLISH\n");
295540622Sbrian          return 1;
295636285Sbrian      }
295740622Sbrian      arg->bundle->ncp.mp.cfg.shortseq &= keep;
295840622Sbrian      arg->bundle->ncp.mp.cfg.shortseq |= add;
295936285Sbrian      break;
296036285Sbrian    case NEG_VJCOMP:
296136285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.neg &= keep;
296236285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.neg |= add;
296336285Sbrian      break;
296436285Sbrian  }
296536285Sbrian
296636285Sbrian  return 0;
296736285Sbrian}
296836285Sbrian
296936285Sbrianstatic struct cmdtab const NegotiateCommands[] = {
2970138799Sbrian  {"echo", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX, "Send echo requests",
2971138799Sbrian  "disable|enable", (const void *)NEG_ECHO},
297262778Sbrian  {"filter-decapsulation", NULL, OptSet, LOCAL_AUTH,
297362778Sbrian  "filter on PPPoUDP payloads", "disable|enable",
297462778Sbrian  (const void *)OPT_FILTERDECAP},
2975112659Sbrian  {"force-scripts", NULL, OptSet, LOCAL_AUTH,
2976112659Sbrian   "Force execution of the configured chat scripts", "disable|enable",
2977112659Sbrian   (const void *)OPT_FORCE_SCRIPTS},
297836285Sbrian  {"idcheck", NULL, OptSet, LOCAL_AUTH, "Check FSM reply ids",
297936285Sbrian  "disable|enable", (const void *)OPT_IDCHECK},
298040666Sbrian  {"iface-alias", NULL, IfaceAliasOptSet, LOCAL_AUTH,
298162778Sbrian  "retain interface addresses", "disable|enable",
298262778Sbrian  (const void *)OPT_IFACEALIAS},
298381634Sbrian#ifndef NOINET6
298481634Sbrian  {"ipcp", NULL, OptSet, LOCAL_AUTH, "IP Network Control Protocol",
298581634Sbrian  "disable|enable", (const void *)OPT_IPCP},
298681634Sbrian  {"ipv6cp", NULL, OptSet, LOCAL_AUTH, "IPv6 Network Control Protocol",
298781634Sbrian  "disable|enable", (const void *)OPT_IPV6CP},
298881634Sbrian#endif
298947689Sbrian  {"keep-session", NULL, OptSet, LOCAL_AUTH, "Retain device session leader",
299047689Sbrian  "disable|enable", (const void *)OPT_KEEPSESSION},
299136285Sbrian  {"loopback", NULL, OptSet, LOCAL_AUTH, "Loop packets for local iface",
299236285Sbrian  "disable|enable", (const void *)OPT_LOOPBACK},
2993138198Sbrian  {"nas-ip-address", NULL, OptSet, LOCAL_AUTH, "Send NAS-IP-Address to RADIUS",
2994138198Sbrian  "disable|enable", (const void *)OPT_NAS_IP_ADDRESS},
2995138198Sbrian  {"nas-identifier", NULL, OptSet, LOCAL_AUTH, "Send NAS-Identifier to RADIUS",
2996138198Sbrian  "disable|enable", (const void *)OPT_NAS_IDENTIFIER},
299736285Sbrian  {"passwdauth", NULL, OptSet, LOCAL_AUTH, "Use passwd file",
299836285Sbrian  "disable|enable", (const void *)OPT_PASSWDAUTH},
299940665Sbrian  {"proxy", NULL, OptSet, LOCAL_AUTH, "Create a proxy ARP entry",
300036285Sbrian  "disable|enable", (const void *)OPT_PROXY},
300140665Sbrian  {"proxyall", NULL, OptSet, LOCAL_AUTH, "Proxy ARP for all remote hosts",
300240665Sbrian  "disable|enable", (const void *)OPT_PROXYALL},
300336285Sbrian  {"sroutes", NULL, OptSet, LOCAL_AUTH, "Use sticky routes",
300436285Sbrian  "disable|enable", (const void *)OPT_SROUTES},
300569303Sbrian  {"tcpmssfixup", "mssfixup", OptSet, LOCAL_AUTH, "Modify MSS options",
300669303Sbrian  "disable|enable", (const void *)OPT_TCPMSSFIXUP},
300736285Sbrian  {"throughput", NULL, OptSet, LOCAL_AUTH, "Rolling throughput",
300836285Sbrian  "disable|enable", (const void *)OPT_THROUGHPUT},
300936285Sbrian  {"utmp", NULL, OptSet, LOCAL_AUTH, "Log connections in utmp",
301036285Sbrian  "disable|enable", (const void *)OPT_UTMP},
301136285Sbrian
301281634Sbrian#ifndef NOINET6
3013138799Sbrian#define NEG_OPT_MAX 17	/* accept/deny allowed below and not above */
301481634Sbrian#else
3015138799Sbrian#define NEG_OPT_MAX 15
301681634Sbrian#endif
301736285Sbrian
301836285Sbrian  {"acfcomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
301936285Sbrian  "Address & Control field compression", "accept|deny|disable|enable",
302036285Sbrian  (const void *)NEG_ACFCOMP},
302144106Sbrian  {"chap", "chap05", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
302236285Sbrian  "Challenge Handshake Authentication Protocol", "accept|deny|disable|enable",
302344106Sbrian  (const void *)NEG_CHAP05},
302493418Sbrian#ifndef NODES
302544106Sbrian  {"mschap", "chap80nt", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
302644106Sbrian  "Microsoft (NT) CHAP", "accept|deny|disable|enable",
302744106Sbrian  (const void *)NEG_CHAP80},
302844106Sbrian  {"LANMan", "chap80lm", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
302944106Sbrian  "Microsoft (NT) CHAP", "accept|deny|disable|enable",
303044106Sbrian  (const void *)NEG_CHAP80LM},
303167910Sbrian  {"mschapv2", "chap81", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
303267910Sbrian  "Microsoft CHAP v2", "accept|deny|disable|enable",
303367910Sbrian  (const void *)NEG_CHAP81},
303467910Sbrian  {"mppe", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
303567910Sbrian  "MPPE encryption", "accept|deny|disable|enable",
303667910Sbrian  (const void *)NEG_MPPE},
303744106Sbrian#endif
303836285Sbrian  {"deflate", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
303936285Sbrian  "Deflate compression", "accept|deny|disable|enable",
304036285Sbrian  (const void *)NEG_DEFLATE},
304136285Sbrian  {"deflate24", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
304236285Sbrian  "Deflate (type 24) compression", "accept|deny|disable|enable",
304336285Sbrian  (const void *)NEG_PPPDDEFLATE},
304436285Sbrian  {"dns", NULL, NegotiateSet, LOCAL_AUTH,
304536285Sbrian  "DNS specification", "accept|deny|disable|enable", (const void *)NEG_DNS},
304647858Sbrian  {"enddisc", NULL, NegotiateSet, LOCAL_AUTH, "ENDDISC negotiation",
304747858Sbrian  "accept|deny|disable|enable", (const void *)NEG_ENDDISC},
304836285Sbrian  {"lqr", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
304936285Sbrian  "Link Quality Reports", "accept|deny|disable|enable",
305036285Sbrian  (const void *)NEG_LQR},
305136285Sbrian  {"pap", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
305236285Sbrian  "Password Authentication protocol", "accept|deny|disable|enable",
305336285Sbrian  (const void *)NEG_PAP},
305436285Sbrian  {"pred1", "predictor1", NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
305536285Sbrian  "Predictor 1 compression", "accept|deny|disable|enable",
305636285Sbrian  (const void *)NEG_PRED1},
305736285Sbrian  {"protocomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
305836285Sbrian  "Protocol field compression", "accept|deny|disable|enable",
305936285Sbrian  (const void *)NEG_PROTOCOMP},
306036285Sbrian  {"shortseq", NULL, NegotiateSet, LOCAL_AUTH,
306136285Sbrian  "MP Short Sequence Numbers", "accept|deny|disable|enable",
306236285Sbrian  (const void *)NEG_SHORTSEQ},
306336285Sbrian  {"vjcomp", NULL, NegotiateSet, LOCAL_AUTH,
306436285Sbrian  "Van Jacobson header compression", "accept|deny|disable|enable",
306536285Sbrian  (const void *)NEG_VJCOMP},
306636285Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
306736285Sbrian  "Display this message", "accept|deny|disable|enable help|? [value]",
306836285Sbrian  NegotiateCommands},
3069134789Sbrian  {NULL, NULL, NULL, 0, NULL, NULL, NULL},
307036285Sbrian};
307136285Sbrian
307236285Sbrianstatic int
307336285SbrianNegotiateCommand(struct cmdargs const *arg)
307436285Sbrian{
307536285Sbrian  if (arg->argc > arg->argn) {
307636285Sbrian    char const *argv[3];
307736285Sbrian    unsigned keep, add;
307836285Sbrian    int n;
307936285Sbrian
308036285Sbrian    if ((argv[0] = ident_cmd(arg->argv[arg->argn-1], &keep, &add)) == NULL)
308136285Sbrian      return -1;
308236285Sbrian    argv[2] = NULL;
308336285Sbrian
308436285Sbrian    for (n = arg->argn; n < arg->argc; n++) {
308536285Sbrian      argv[1] = arg->argv[n];
308636285Sbrian      FindExec(arg->bundle, NegotiateCommands + (keep == NEG_HISMASK ?
3087138198Sbrian               0 : NEG_OPT_MAX), 2, 1, argv, arg->prompt, arg->cx);
308836285Sbrian    }
308936285Sbrian  } else if (arg->prompt)
309036285Sbrian    prompt_Printf(arg->prompt, "Use `%s ?' to get a list.\n",
309136285Sbrian	    arg->argv[arg->argn-1]);
309236285Sbrian  else
309336285Sbrian    log_Printf(LogWARN, "%s command must have arguments\n",
309436285Sbrian              arg->argv[arg->argn] );
309536285Sbrian
309636285Sbrian  return 0;
309736285Sbrian}
309836285Sbrian
309936285Sbrianconst char *
310036285Sbriancommand_ShowNegval(unsigned val)
310136285Sbrian{
310236285Sbrian  switch (val&3) {
310336285Sbrian    case 1: return "disabled & accepted";
310436285Sbrian    case 2: return "enabled & denied";
310536285Sbrian    case 3: return "enabled & accepted";
310636285Sbrian  }
310736285Sbrian  return "disabled & denied";
310836285Sbrian}
310936934Sbrian
311036934Sbrianstatic int
311136934SbrianClearCommand(struct cmdargs const *arg)
311236934Sbrian{
311336934Sbrian  struct pppThroughput *t;
311436934Sbrian  struct datalink *cx;
311536934Sbrian  int i, clear_type;
311636934Sbrian
311736934Sbrian  if (arg->argc < arg->argn + 1)
311836934Sbrian    return -1;
311936934Sbrian
312046686Sbrian  if (strcasecmp(arg->argv[arg->argn], "physical") == 0) {
312136934Sbrian    cx = arg->cx;
312236934Sbrian    if (!cx)
312336934Sbrian      cx = bundle2datalink(arg->bundle, NULL);
312436934Sbrian    if (!cx) {
312546686Sbrian      log_Printf(LogWARN, "A link must be specified for ``clear physical''\n");
312636934Sbrian      return 1;
312736934Sbrian    }
312864652Sbrian    t = &cx->physical->link.stats.total;
312936934Sbrian  } else if (strcasecmp(arg->argv[arg->argn], "ipcp") == 0)
313036934Sbrian    t = &arg->bundle->ncp.ipcp.throughput;
313181634Sbrian#ifndef NOINET6
313281897Sbrian  else if (strcasecmp(arg->argv[arg->argn], "ipv6cp") == 0)
313381634Sbrian    t = &arg->bundle->ncp.ipv6cp.throughput;
313481634Sbrian#endif
313536934Sbrian  else
313636934Sbrian    return -1;
313736934Sbrian
313836934Sbrian  if (arg->argc > arg->argn + 1) {
313936934Sbrian    clear_type = 0;
314036934Sbrian    for (i = arg->argn + 1; i < arg->argc; i++)
314136934Sbrian      if (strcasecmp(arg->argv[i], "overall") == 0)
314236934Sbrian        clear_type |= THROUGHPUT_OVERALL;
314336934Sbrian      else if (strcasecmp(arg->argv[i], "current") == 0)
314436934Sbrian        clear_type |= THROUGHPUT_CURRENT;
314536934Sbrian      else if (strcasecmp(arg->argv[i], "peak") == 0)
314636934Sbrian        clear_type |= THROUGHPUT_PEAK;
314736934Sbrian      else
314836934Sbrian        return -1;
314998243Sbrian  } else
315036934Sbrian    clear_type = THROUGHPUT_ALL;
315136934Sbrian
315236934Sbrian  throughput_clear(t, clear_type, arg->prompt);
315336934Sbrian  return 0;
315436934Sbrian}
315540561Sbrian
315640561Sbrianstatic int
315740561SbrianRunListCommand(struct cmdargs const *arg)
315840561Sbrian{
315940561Sbrian  const char *cmd = arg->argc ? arg->argv[arg->argc - 1] : "???";
316040561Sbrian
316164801Sbrian#ifndef NONAT
316264801Sbrian  if (arg->cmd->args == NatCommands &&
316364801Sbrian      tolower(*arg->argv[arg->argn - 1]) == 'a') {
316464801Sbrian    if (arg->prompt)
316565550Sbrian      prompt_Printf(arg->prompt, "The alias command is deprecated\n");
316664801Sbrian    else
316765550Sbrian      log_Printf(LogWARN, "The alias command is deprecated\n");
316864801Sbrian  }
316964801Sbrian#endif
317064801Sbrian
317140561Sbrian  if (arg->argc > arg->argn)
317240561Sbrian    FindExec(arg->bundle, arg->cmd->args, arg->argc, arg->argn, arg->argv,
317340561Sbrian             arg->prompt, arg->cx);
317440561Sbrian  else if (arg->prompt)
317540561Sbrian    prompt_Printf(arg->prompt, "Use `%s help' to get a list or `%s help"
317640561Sbrian                  " <option>' for syntax help.\n", cmd, cmd);
317740561Sbrian  else
317840561Sbrian    log_Printf(LogWARN, "%s command must have arguments\n", cmd);
317940561Sbrian
318040561Sbrian  return 0;
318140561Sbrian}
318240561Sbrian
318340561Sbrianstatic int
3184218397SbrianIfaceNameCommand(struct cmdargs const *arg)
3185218397Sbrian{
3186218397Sbrian  int n = arg->argn;
3187218397Sbrian
3188218397Sbrian  if (arg->argc != n + 1)
3189218397Sbrian    return -1;
3190218397Sbrian
3191218397Sbrian  if (!iface_Name(arg->bundle->iface, arg->argv[n]))
3192218397Sbrian    return 1;
3193218397Sbrian
3194218397Sbrian  log_SetTun(arg->bundle->unit, arg->bundle->iface->name);
3195218397Sbrian  return 0;
3196218397Sbrian}
3197218397Sbrian
3198218397Sbrianstatic int
319940561SbrianIfaceAddCommand(struct cmdargs const *arg)
320040561Sbrian{
320181634Sbrian  struct ncpaddr peer, addr;
320281634Sbrian  struct ncprange ifa;
320381634Sbrian  struct in_addr mask;
320481634Sbrian  int n, how;
320540561Sbrian
320640664Sbrian  if (arg->argc == arg->argn + 1) {
320781634Sbrian    if (!ncprange_aton(&ifa, NULL, arg->argv[arg->argn]))
320840561Sbrian      return -1;
320981634Sbrian    ncpaddr_init(&peer);
321040664Sbrian  } else {
321140664Sbrian    if (arg->argc == arg->argn + 2) {
321281634Sbrian      if (!ncprange_aton(&ifa, NULL, arg->argv[arg->argn]))
321340664Sbrian        return -1;
321440664Sbrian      n = 1;
321540664Sbrian    } else if (arg->argc == arg->argn + 3) {
321681634Sbrian      if (!ncpaddr_aton(&addr, NULL, arg->argv[arg->argn]))
321740664Sbrian        return -1;
321881634Sbrian      if (ncpaddr_family(&addr) != AF_INET)
321940664Sbrian        return -1;
322081634Sbrian      ncprange_sethost(&ifa, &addr);
322181634Sbrian      if (!ncpaddr_aton(&addr, NULL, arg->argv[arg->argn + 1]))
322281634Sbrian        return -1;
322381634Sbrian      if (!ncpaddr_getip4(&addr, &mask))
322481634Sbrian        return -1;
322581634Sbrian      if (!ncprange_setip4mask(&ifa, mask))
322681634Sbrian        return -1;
322740664Sbrian      n = 2;
322840664Sbrian    } else
322940561Sbrian      return -1;
323040561Sbrian
323181634Sbrian    if (!ncpaddr_aton(&peer, NULL, arg->argv[arg->argn + n]))
323240664Sbrian      return -1;
323381634Sbrian
323481634Sbrian    if (ncprange_family(&ifa) != ncpaddr_family(&peer)) {
323581634Sbrian      log_Printf(LogWARN, "IfaceAddCommand: src and dst address families"
323681634Sbrian                 " differ\n");
323781634Sbrian      return -1;
323881634Sbrian    }
323940664Sbrian  }
324040561Sbrian
324140561Sbrian  how = IFACE_ADD_LAST;
324240561Sbrian  if (arg->cmd->args)
324340561Sbrian    how |= IFACE_FORCE_ADD;
324440561Sbrian
324581634Sbrian  return !iface_Add(arg->bundle->iface, &arg->bundle->ncp, &ifa, &peer, how);
324640561Sbrian}
324740561Sbrian
324840561Sbrianstatic int
324940561SbrianIfaceDeleteCommand(struct cmdargs const *arg)
325040561Sbrian{
325181634Sbrian  struct ncpaddr ifa;
325281634Sbrian  struct in_addr ifa4;
325340561Sbrian  int ok;
325440561Sbrian
325540561Sbrian  if (arg->argc != arg->argn + 1)
325640561Sbrian    return -1;
325740561Sbrian
325881634Sbrian  if (!ncpaddr_aton(&ifa, NULL, arg->argv[arg->argn]))
325940561Sbrian    return -1;
326040561Sbrian
326140561Sbrian  if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED &&
326281634Sbrian      ncpaddr_getip4(&ifa, &ifa4) &&
326381634Sbrian      arg->bundle->ncp.ipcp.my_ip.s_addr == ifa4.s_addr) {
326440561Sbrian    log_Printf(LogWARN, "%s: Cannot remove active interface address\n",
326581634Sbrian               ncpaddr_ntoa(&ifa));
326640561Sbrian    return 1;
326740561Sbrian  }
326840561Sbrian
326981634Sbrian  ok = iface_Delete(arg->bundle->iface, &arg->bundle->ncp, &ifa);
327040561Sbrian  if (!ok) {
327140561Sbrian    if (arg->cmd->args)
327240561Sbrian      ok = 1;
327340561Sbrian    else if (arg->prompt)
327481634Sbrian      prompt_Printf(arg->prompt, "%s: No such interface address\n",
327581634Sbrian                    ncpaddr_ntoa(&ifa));
327640561Sbrian    else
327781634Sbrian      log_Printf(LogWARN, "%s: No such interface address\n",
327881634Sbrian                 ncpaddr_ntoa(&ifa));
327940561Sbrian  }
328040561Sbrian
328140561Sbrian  return !ok;
328240561Sbrian}
328340561Sbrian
328440561Sbrianstatic int
328540561SbrianIfaceClearCommand(struct cmdargs const *arg)
328640561Sbrian{
328781634Sbrian  int family, how;
328840561Sbrian
328981634Sbrian  family = 0;
329081634Sbrian  if (arg->argc == arg->argn + 1) {
329181634Sbrian    if (strcasecmp(arg->argv[arg->argn], "inet") == 0)
329281634Sbrian      family = AF_INET;
329381634Sbrian#ifndef NOINET6
329481897Sbrian    else if (strcasecmp(arg->argv[arg->argn], "inet6") == 0)
329581634Sbrian      family = AF_INET6;
329681634Sbrian#endif
329781634Sbrian    else
329881634Sbrian      return -1;
329981634Sbrian  } else if (arg->argc != arg->argn)
330040561Sbrian    return -1;
330140561Sbrian
330240941Sbrian  how = arg->bundle->ncp.ipcp.fsm.state == ST_OPENED ||
330340941Sbrian        arg->bundle->phys_type.all & PHYS_AUTO ?
330440561Sbrian        IFACE_CLEAR_ALIASES : IFACE_CLEAR_ALL;
330581634Sbrian  iface_Clear(arg->bundle->iface, &arg->bundle->ncp, family, how);
330640561Sbrian
330740561Sbrian  return 0;
330840561Sbrian}
330940679Sbrian
331040679Sbrianstatic int
331140679SbrianSetProcTitle(struct cmdargs const *arg)
331240679Sbrian{
331340679Sbrian  static char title[LINE_LEN];
331486028Sbrian  char *argv[MAXARGS];
331586028Sbrian  int argc = arg->argc - arg->argn;
331640679Sbrian
3317134789Sbrian  if (arg->argc <= arg->argn) {
331864698Sbrian    SetTitle(NULL);
331940679Sbrian    return 0;
332040679Sbrian  }
332140679Sbrian
3322134789Sbrian  if ((unsigned)argc >= sizeof argv / sizeof argv[0]) {
332340679Sbrian    argc = sizeof argv / sizeof argv[0] - 1;
332440679Sbrian    log_Printf(LogWARN, "Truncating proc title to %d args\n", argc);
332540679Sbrian  }
332647849Sbrian  command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 1, getpid());
332785991Sbrian  Concatinate(title, sizeof title, argc, (const char *const *)argv);
332864698Sbrian  SetTitle(title);
332985991Sbrian  command_Free(argc, argv);
333040679Sbrian
333140679Sbrian  return 0;
333240679Sbrian}
3333