command.c revision 132818
178189Sbrian/*-
278189Sbrian * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org>
378189Sbrian *          based on work by Toshiharu OHNO <tony-o@iij.ad.jp>
478189Sbrian *                           Internet Initiative Japan, Inc (IIJ)
578189Sbrian * All rights reserved.
66059Samurai *
778189Sbrian * Redistribution and use in source and binary forms, with or without
878189Sbrian * modification, are permitted provided that the following conditions
978189Sbrian * are met:
1078189Sbrian * 1. Redistributions of source code must retain the above copyright
1178189Sbrian *    notice, this list of conditions and the following disclaimer.
1278189Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1378189Sbrian *    notice, this list of conditions and the following disclaimer in the
1478189Sbrian *    documentation and/or other materials provided with the distribution.
156059Samurai *
1678189Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1778189Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1878189Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1978189Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2078189Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2178189Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2278189Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2378189Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2478189Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2578189Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2678189Sbrian * SUCH DAMAGE.
276059Samurai *
2850479Speter * $FreeBSD: head/usr.sbin/ppp/command.c 132818 2004-07-29 05:59:43Z glebius $
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
1476059Samurai
14836285Sbrian/* ``accept|deny|disable|enable'' masks */
14936285Sbrian#define NEG_HISMASK (1)
15036285Sbrian#define NEG_MYMASK (2)
15136285Sbrian
15236285Sbrian/* ``accept|deny|disable|enable'' values */
15336285Sbrian#define NEG_ACFCOMP	40
15444106Sbrian#define NEG_CHAP05	41
15544106Sbrian#define NEG_CHAP80	42
15644106Sbrian#define NEG_CHAP80LM	43
15744106Sbrian#define NEG_DEFLATE	44
15847858Sbrian#define NEG_DNS		45
15947858Sbrian#define NEG_ENDDISC	46
16047858Sbrian#define NEG_LQR		47
16147858Sbrian#define NEG_PAP		48
16247858Sbrian#define NEG_PPPDDEFLATE	49
16347858Sbrian#define NEG_PRED1	50
16447858Sbrian#define NEG_PROTOCOMP	51
16547858Sbrian#define NEG_SHORTSEQ	52
16647858Sbrian#define NEG_VJCOMP	53
16767910Sbrian#define NEG_MPPE	54
16867910Sbrian#define NEG_CHAP81	55
16936285Sbrian
170132273Sbrianconst char Version[] = "3.2";
17136285Sbrian
17236285Sbrianstatic int ShowCommand(struct cmdargs const *);
17336285Sbrianstatic int TerminalCommand(struct cmdargs const *);
17436285Sbrianstatic int QuitCommand(struct cmdargs const *);
17536285Sbrianstatic int OpenCommand(struct cmdargs const *);
17636285Sbrianstatic int CloseCommand(struct cmdargs const *);
17736285Sbrianstatic int DownCommand(struct cmdargs const *);
17836285Sbrianstatic int SetCommand(struct cmdargs const *);
17936285Sbrianstatic int LinkCommand(struct cmdargs const *);
18036285Sbrianstatic int AddCommand(struct cmdargs const *);
18136285Sbrianstatic int DeleteCommand(struct cmdargs const *);
18236285Sbrianstatic int NegotiateCommand(struct cmdargs const *);
18336934Sbrianstatic int ClearCommand(struct cmdargs const *);
18440561Sbrianstatic int RunListCommand(struct cmdargs const *);
18540561Sbrianstatic int IfaceAddCommand(struct cmdargs const *);
18640561Sbrianstatic int IfaceDeleteCommand(struct cmdargs const *);
18740561Sbrianstatic int IfaceClearCommand(struct cmdargs const *);
18840679Sbrianstatic int SetProcTitle(struct cmdargs const *);
18950059Sbrian#ifndef NONAT
19058867Sbrianstatic int NatEnable(struct cmdargs const *);
19158867Sbrianstatic int NatOption(struct cmdargs const *);
19231343Sbrian#endif
1936059Samurai
19436285Sbrianstatic const char *
19536285Sbrianshowcx(struct cmdtab const *cmd)
19636285Sbrian{
19736285Sbrian  if (cmd->lauth & LOCAL_CX)
19836285Sbrian    return "(c)";
19936285Sbrian  else if (cmd->lauth & LOCAL_CX_OPT)
20036285Sbrian    return "(o)";
20136285Sbrian
20236285Sbrian  return "";
20336285Sbrian}
20436285Sbrian
2056059Samuraistatic int
20631343SbrianHelpCommand(struct cmdargs const *arg)
2076059Samurai{
20828679Sbrian  struct cmdtab const *cmd;
20936285Sbrian  int n, cmax, dmax, cols, cxlen;
21036285Sbrian  const char *cx;
2116059Samurai
21236285Sbrian  if (!arg->prompt) {
21336285Sbrian    log_Printf(LogWARN, "help: Cannot help without a prompt\n");
21426516Sbrian    return 0;
21536285Sbrian  }
21626516Sbrian
21736285Sbrian  if (arg->argc > arg->argn) {
21836285Sbrian    for (cmd = arg->cmdtab; cmd->name || cmd->alias; cmd++)
21936285Sbrian      if ((cmd->lauth & arg->prompt->auth) &&
22036285Sbrian          ((cmd->name && !strcasecmp(cmd->name, arg->argv[arg->argn])) ||
22136285Sbrian           (cmd->alias && !strcasecmp(cmd->alias, arg->argv[arg->argn])))) {
22236285Sbrian	prompt_Printf(arg->prompt, "%s %s\n", cmd->syntax, showcx(cmd));
22328679Sbrian	return 0;
2246059Samurai      }
22526516Sbrian    return -1;
2266059Samurai  }
22736285Sbrian
22831372Sbrian  cmax = dmax = 0;
22936285Sbrian  for (cmd = arg->cmdtab; cmd->func; cmd++)
23036285Sbrian    if (cmd->name && (cmd->lauth & arg->prompt->auth)) {
23136285Sbrian      if ((n = strlen(cmd->name) + strlen(showcx(cmd))) > cmax)
23231372Sbrian        cmax = n;
23331372Sbrian      if ((n = strlen(cmd->helpmes)) > dmax)
23431372Sbrian        dmax = n;
23531372Sbrian    }
23631372Sbrian
23731372Sbrian  cols = 80 / (dmax + cmax + 3);
2386059Samurai  n = 0;
23936285Sbrian  prompt_Printf(arg->prompt, "(o) = Optional context,"
24036285Sbrian                " (c) = Context required\n");
24136285Sbrian  for (cmd = arg->cmdtab; cmd->func; cmd++)
24236285Sbrian    if (cmd->name && (cmd->lauth & arg->prompt->auth)) {
24336285Sbrian      cx = showcx(cmd);
24436285Sbrian      cxlen = cmax - strlen(cmd->name);
24540482Sbrian      if (n % cols != 0)
24640482Sbrian        prompt_Printf(arg->prompt, " ");
24740482Sbrian      prompt_Printf(arg->prompt, "%s%-*.*s: %-*.*s",
24836285Sbrian              cmd->name, cxlen, cxlen, cx, dmax, dmax, cmd->helpmes);
24931372Sbrian      if (++n % cols == 0)
25036285Sbrian        prompt_Printf(arg->prompt, "\n");
2516059Samurai    }
25231372Sbrian  if (n % cols != 0)
25336285Sbrian    prompt_Printf(arg->prompt, "\n");
25426516Sbrian
25526516Sbrian  return 0;
2566059Samurai}
2576059Samurai
25836285Sbrianstatic int
25963484SbrianIdentCommand(struct cmdargs const *arg)
26063484Sbrian{
26185991Sbrian  Concatinate(arg->cx->physical->link.lcp.cfg.ident,
26285991Sbrian              sizeof arg->cx->physical->link.lcp.cfg.ident,
26385991Sbrian              arg->argc - arg->argn, arg->argv + arg->argn);
26463484Sbrian  return 0;
26563484Sbrian}
26663484Sbrian
26763484Sbrianstatic int
26863484SbrianSendIdentification(struct cmdargs const *arg)
26963484Sbrian{
27063484Sbrian  if (arg->cx->state < DATALINK_LCP) {
27163484Sbrian    log_Printf(LogWARN, "sendident: link has not reached LCP\n");
27263484Sbrian    return 2;
27363484Sbrian  }
27463484Sbrian  return lcp_SendIdentification(&arg->cx->physical->link.lcp) ? 0 : 1;
27563484Sbrian}
27663484Sbrian
27763484Sbrianstatic int
27836285SbrianCloneCommand(struct cmdargs const *arg)
2796059Samurai{
28036285Sbrian  char namelist[LINE_LEN];
28136285Sbrian  char *name;
28236285Sbrian  int f;
2836059Samurai
28436285Sbrian  if (arg->argc == arg->argn)
28536285Sbrian    return -1;
28636285Sbrian
28736285Sbrian  namelist[sizeof namelist - 1] = '\0';
28836285Sbrian  for (f = arg->argn; f < arg->argc; f++) {
28936285Sbrian    strncpy(namelist, arg->argv[f], sizeof namelist - 1);
29036285Sbrian    for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
29136285Sbrian      bundle_DatalinkClone(arg->bundle, arg->cx, name);
2926059Samurai  }
29336285Sbrian
29436285Sbrian  return 0;
2956059Samurai}
2966059Samurai
2976059Samuraistatic int
29836285SbrianRemoveCommand(struct cmdargs const *arg)
2996059Samurai{
30036285Sbrian  if (arg->argc != arg->argn)
30136285Sbrian    return -1;
30211336Samurai
30336285Sbrian  if (arg->cx->state != DATALINK_CLOSED) {
30436285Sbrian    log_Printf(LogWARN, "remove: Cannot delete links that aren't closed\n");
30536285Sbrian    return 2;
3066059Samurai  }
30726516Sbrian
30836285Sbrian  bundle_DatalinkRemove(arg->bundle, arg->cx);
30936285Sbrian  return 0;
31036285Sbrian}
31132711Sbrian
31236285Sbrianstatic int
31336285SbrianRenameCommand(struct cmdargs const *arg)
31436285Sbrian{
31536285Sbrian  if (arg->argc != arg->argn + 1)
31636285Sbrian    return -1;
31731121Sbrian
31836285Sbrian  if (bundle_RenameDatalink(arg->bundle, arg->cx, arg->argv[arg->argn]))
31936285Sbrian    return 0;
32036285Sbrian
32198243Sbrian  log_Printf(LogWARN, "%s -> %s: target name already exists\n",
32236285Sbrian             arg->cx->name, arg->argv[arg->argn]);
32336285Sbrian  return 1;
32436285Sbrian}
32536285Sbrian
32685991Sbrianstatic int
32736285SbrianLoadCommand(struct cmdargs const *arg)
32836285Sbrian{
32940797Sbrian  const char *err;
33040797Sbrian  int n, mode;
33136285Sbrian
33240797Sbrian  mode = arg->bundle->phys_type.all;
33336285Sbrian
33440797Sbrian  if (arg->argn < arg->argc) {
33540797Sbrian    for (n = arg->argn; n < arg->argc; n++)
33640797Sbrian      if ((err = system_IsValid(arg->argv[n], arg->prompt, mode)) != NULL) {
33740797Sbrian        log_Printf(LogWARN, "%s: %s\n", arg->argv[n], err);
33840797Sbrian        return 1;
33940797Sbrian      }
34040797Sbrian
34140797Sbrian    for (n = arg->argn; n < arg->argc; n++) {
34240797Sbrian      bundle_SetLabel(arg->bundle, arg->argv[arg->argc - 1]);
34340797Sbrian      system_Select(arg->bundle, arg->argv[n], CONFFILE, arg->prompt, arg->cx);
34440797Sbrian    }
34540797Sbrian    bundle_SetLabel(arg->bundle, arg->argv[arg->argc - 1]);
34640797Sbrian  } else if ((err = system_IsValid("default", arg->prompt, mode)) != NULL) {
34740797Sbrian    log_Printf(LogWARN, "default: %s\n", err);
34836285Sbrian    return 1;
34936285Sbrian  } else {
35040797Sbrian    bundle_SetLabel(arg->bundle, "default");
35140797Sbrian    system_Select(arg->bundle, "default", CONFFILE, arg->prompt, arg->cx);
35240797Sbrian    bundle_SetLabel(arg->bundle, "default");
35336285Sbrian  }
35440797Sbrian
35526516Sbrian  return 0;
3566059Samurai}
3576059Samurai
35885991Sbrianstatic int
35985991SbrianLogCommand(struct cmdargs const *arg)
36085991Sbrian{
36185991Sbrian  char buf[LINE_LEN];
36285991Sbrian
36385991Sbrian  if (arg->argn < arg->argc) {
36485991Sbrian    char *argv[MAXARGS];
36585991Sbrian    int argc = arg->argc - arg->argn;
36685991Sbrian
36785991Sbrian    if (argc >= sizeof argv / sizeof argv[0]) {
36885991Sbrian      argc = sizeof argv / sizeof argv[0] - 1;
36985991Sbrian      log_Printf(LogWARN, "Truncating log command to %d args\n", argc);
37085991Sbrian    }
37186760Sbrian    command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 1, getpid());
37285991Sbrian    Concatinate(buf, sizeof buf, argc, (const char *const *)argv);
37385991Sbrian    log_Printf(LogLOG, "%s\n", buf);
37485991Sbrian    command_Free(argc, argv);
37585991Sbrian    return 0;
37685991Sbrian  }
37785991Sbrian
37885991Sbrian  return -1;
37985991Sbrian}
38085991Sbrian
38185991Sbrianstatic int
38236285SbrianSaveCommand(struct cmdargs const *arg)
38336285Sbrian{
38485991Sbrian  log_Printf(LogWARN, "save command is not yet implemented.\n");
38536285Sbrian  return 1;
38636285Sbrian}
38736285Sbrian
38810528Samuraistatic int
38936285SbrianDialCommand(struct cmdargs const *arg)
39028536Sbrian{
39136285Sbrian  int res;
39236285Sbrian
39336465Sbrian  if ((arg->cx && !(arg->cx->physical->type & (PHYS_INTERACTIVE|PHYS_AUTO)))
39436465Sbrian      || (!arg->cx &&
39536928Sbrian          (arg->bundle->phys_type.all & ~(PHYS_INTERACTIVE|PHYS_AUTO)))) {
39636285Sbrian    log_Printf(LogWARN, "Manual dial is only available for auto and"
39736285Sbrian              " interactive links\n");
39836285Sbrian    return 1;
39934536Sbrian  }
40036285Sbrian
40136285Sbrian  if (arg->argc > arg->argn && (res = LoadCommand(arg)) != 0)
40236285Sbrian    return res;
40336285Sbrian
40437993Sbrian  bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1);
40536285Sbrian
40636285Sbrian  return 0;
40728536Sbrian}
40828536Sbrian
40938628Sbrian#define isinword(ch) (isalnum(ch) || (ch) == '_')
41038628Sbrian
41138628Sbrianstatic char *
41238628Sbrianstrstrword(char *big, const char *little)
41338628Sbrian{
41438628Sbrian  /* Get the first occurance of the word ``little'' in ``big'' */
41538628Sbrian  char *pos;
41638628Sbrian  int len;
41738628Sbrian
41838628Sbrian  pos = big;
41938628Sbrian  len = strlen(little);
42038628Sbrian
42138628Sbrian  while ((pos = strstr(pos, little)) != NULL)
42247865Sbrian    if ((pos != big && isinword(pos[-1])) || isinword(pos[len]))
42347865Sbrian      pos++;
42447865Sbrian    else if (pos != big && pos[-1] == '\\')
42547865Sbrian      memmove(pos - 1, pos, strlen(pos) + 1);
42647865Sbrian    else
42738628Sbrian      break;
42838628Sbrian
42938628Sbrian  return pos;
43038628Sbrian}
43138628Sbrian
43238628Sbrianstatic char *
43338628Sbriansubst(char *tgt, const char *oldstr, const char *newstr)
43438628Sbrian{
43538628Sbrian  /* tgt is a malloc()d area... realloc() as necessary */
43638628Sbrian  char *word, *ntgt;
43738628Sbrian  int ltgt, loldstr, lnewstr, pos;
43838628Sbrian
43938628Sbrian  if ((word = strstrword(tgt, oldstr)) == NULL)
44038628Sbrian    return tgt;
44138628Sbrian
44238628Sbrian  ltgt = strlen(tgt) + 1;
44338628Sbrian  loldstr = strlen(oldstr);
44438628Sbrian  lnewstr = strlen(newstr);
44538628Sbrian  do {
44638628Sbrian    pos = word - tgt;
44738628Sbrian    if (loldstr > lnewstr)
44838628Sbrian      bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr);
44938628Sbrian    if (loldstr != lnewstr) {
45038628Sbrian      ntgt = realloc(tgt, ltgt += lnewstr - loldstr);
45138628Sbrian      if (ntgt == NULL)
45238628Sbrian        break;			/* Oh wonderful ! */
45338628Sbrian      word = ntgt + pos;
45438628Sbrian      tgt = ntgt;
45538628Sbrian    }
45638628Sbrian    if (lnewstr > loldstr)
45738628Sbrian      bcopy(word + loldstr, word + lnewstr, ltgt - pos - loldstr);
45838628Sbrian    bcopy(newstr, word, lnewstr);
45938628Sbrian  } while ((word = strstrword(word, oldstr)));
46038628Sbrian
46138628Sbrian  return tgt;
46238628Sbrian}
46338628Sbrian
46494934Sbrianstatic char *
46594934Sbriansubstip(char *tgt, const char *oldstr, struct in_addr ip)
46694934Sbrian{
46794934Sbrian  return subst(tgt, oldstr, inet_ntoa(ip));
46894934Sbrian}
46994934Sbrian
47094934Sbrianstatic char *
47197360Sbriansubstlong(char *tgt, const char *oldstr, long l)
47294934Sbrian{
47397360Sbrian  char buf[23];
47494934Sbrian
47597360Sbrian  snprintf(buf, sizeof buf, "%ld", l);
47694934Sbrian
47794934Sbrian  return subst(tgt, oldstr, buf);
47894934Sbrian}
47994934Sbrian
48094934Sbrianstatic char *
48194934Sbriansubstull(char *tgt, const char *oldstr, unsigned long long ull)
48294934Sbrian{
48394934Sbrian  char buf[21];
48494934Sbrian
48594934Sbrian  snprintf(buf, sizeof buf, "%llu", ull);
48694934Sbrian
48794934Sbrian  return subst(tgt, oldstr, buf);
48894934Sbrian}
48994934Sbrian
49094934Sbrian
49194934Sbrian#ifndef NOINET6
49294934Sbrianstatic char *
49394934Sbriansubstipv6(char *tgt, const char *oldstr, const struct ncpaddr *ip)
49494934Sbrian{
49594934Sbrian    return subst(tgt, oldstr, ncpaddr_ntoa(ip));
49694934Sbrian}
497116622Sume
498116622Sume#ifndef NORADIUS
499116622Sumestatic char *
500116622Sumesubstipv6prefix(char *tgt, const char *oldstr, const uint8_t *ipv6prefix)
501116622Sume{
502116622Sume  uint8_t ipv6addr[INET6_ADDRSTRLEN];
503116622Sume  uint8_t prefix[INET6_ADDRSTRLEN + sizeof("/128") - 1];
504116622Sume
505116622Sume  if (ipv6prefix) {
506116622Sume    inet_ntop(AF_INET6, &ipv6prefix[2], ipv6addr, sizeof(ipv6addr));
507116622Sume    snprintf(prefix, sizeof(prefix), "%s/%d", ipv6addr, ipv6prefix[1]);
508116622Sume  } else
509116622Sume    prefix[0] = '\0';
510116622Sume  return subst(tgt, oldstr, prefix);
511116622Sume}
51294934Sbrian#endif
513116622Sume#endif
51494934Sbrian
51543888Sbrianvoid
51643888Sbriancommand_Expand(char **nargv, int argc, char const *const *oargv,
51747849Sbrian               struct bundle *bundle, int inc0, pid_t pid)
51838628Sbrian{
51985991Sbrian  int arg, secs;
52094934Sbrian  char uptime[20];
52194934Sbrian  unsigned long long oin, oout, pin, pout;
52238628Sbrian
52341755Sbrian  if (inc0)
52441755Sbrian    arg = 0;		/* Start at arg 0 */
52541755Sbrian  else {
52641755Sbrian    nargv[0] = strdup(oargv[0]);
52741755Sbrian    arg = 1;
52841755Sbrian  }
52994934Sbrian
53094934Sbrian  secs = bundle_Uptime(bundle);
53194934Sbrian  snprintf(uptime, sizeof uptime, "%d:%02d:%02d",
53294934Sbrian           secs / 3600, (secs / 60) % 60, secs % 60);
53394934Sbrian  oin = bundle->ncp.ipcp.throughput.OctetsIn;
53494934Sbrian  oout = bundle->ncp.ipcp.throughput.OctetsOut;
53594934Sbrian  pin = bundle->ncp.ipcp.throughput.PacketsIn;
53694934Sbrian  pout = bundle->ncp.ipcp.throughput.PacketsOut;
53794934Sbrian#ifndef NOINET6
53894934Sbrian  oin += bundle->ncp.ipv6cp.throughput.OctetsIn;
53994934Sbrian  oout += bundle->ncp.ipv6cp.throughput.OctetsOut;
54094934Sbrian  pin += bundle->ncp.ipv6cp.throughput.PacketsIn;
54194934Sbrian  pout += bundle->ncp.ipv6cp.throughput.PacketsOut;
54294934Sbrian#endif
54394934Sbrian
54441755Sbrian  for (; arg < argc; arg++) {
54538629Sbrian    nargv[arg] = strdup(oargv[arg]);
54694934Sbrian    nargv[arg] = subst(nargv[arg], "AUTHNAME", bundle->cfg.auth.name);
54794934Sbrian    nargv[arg] = subst(nargv[arg], "COMPILATIONDATE", __DATE__);
54894934Sbrian    nargv[arg] = substip(nargv[arg], "DNS0", bundle->ncp.ipcp.ns.dns[0]);
54994934Sbrian    nargv[arg] = substip(nargv[arg], "DNS1", bundle->ncp.ipcp.ns.dns[1]);
55098243Sbrian    nargv[arg] = subst(nargv[arg], "ENDDISC",
55194934Sbrian                       mp_Enddisc(bundle->ncp.mp.cfg.enddisc.class,
55294934Sbrian                                  bundle->ncp.mp.cfg.enddisc.address,
55394934Sbrian                                  bundle->ncp.mp.cfg.enddisc.len));
55494934Sbrian    nargv[arg] = substip(nargv[arg], "HISADDR", bundle->ncp.ipcp.peer_ip);
55581634Sbrian#ifndef NOINET6
55694934Sbrian    nargv[arg] = substipv6(nargv[arg], "HISADDR6", &bundle->ncp.ipv6cp.hisaddr);
55781634Sbrian#endif
55840561Sbrian    nargv[arg] = subst(nargv[arg], "INTERFACE", bundle->iface->name);
55994934Sbrian    nargv[arg] = substull(nargv[arg], "IPOCTETSIN",
56094934Sbrian                          bundle->ncp.ipcp.throughput.OctetsIn);
56198243Sbrian    nargv[arg] = substull(nargv[arg], "IPOCTETSOUT",
56294934Sbrian                          bundle->ncp.ipcp.throughput.OctetsOut);
56398243Sbrian    nargv[arg] = substull(nargv[arg], "IPPACKETSIN",
56494934Sbrian                          bundle->ncp.ipcp.throughput.PacketsIn);
56598243Sbrian    nargv[arg] = substull(nargv[arg], "IPPACKETSOUT",
56694934Sbrian                          bundle->ncp.ipcp.throughput.PacketsOut);
56781634Sbrian#ifndef NOINET6
56898243Sbrian    nargv[arg] = substull(nargv[arg], "IPV6OCTETSIN",
56994934Sbrian                          bundle->ncp.ipv6cp.throughput.OctetsIn);
57098243Sbrian    nargv[arg] = substull(nargv[arg], "IPV6OCTETSOUT",
57194934Sbrian                          bundle->ncp.ipv6cp.throughput.OctetsOut);
57298243Sbrian    nargv[arg] = substull(nargv[arg], "IPV6PACKETSIN",
57394934Sbrian                          bundle->ncp.ipv6cp.throughput.PacketsIn);
57498243Sbrian    nargv[arg] = substull(nargv[arg], "IPV6PACKETSOUT",
57594934Sbrian                          bundle->ncp.ipv6cp.throughput.PacketsOut);
57681634Sbrian#endif
57794934Sbrian    nargv[arg] = subst(nargv[arg], "LABEL", bundle_GetLabel(bundle));
57894934Sbrian    nargv[arg] = substip(nargv[arg], "MYADDR", bundle->ncp.ipcp.my_ip);
57994934Sbrian#ifndef NOINET6
58094934Sbrian    nargv[arg] = substipv6(nargv[arg], "MYADDR6", &bundle->ncp.ipv6cp.myaddr);
581116622Sume#ifndef NORADIUS
582116622Sume    nargv[arg] = substipv6prefix(nargv[arg], "IPV6PREFIX",
583116622Sume				 bundle->radius.ipv6prefix);
58494934Sbrian#endif
585116622Sume#endif
58694934Sbrian    nargv[arg] = substull(nargv[arg], "OCTETSIN", oin);
58794934Sbrian    nargv[arg] = substull(nargv[arg], "OCTETSOUT", oout);
58894934Sbrian    nargv[arg] = substull(nargv[arg], "PACKETSIN", pin);
58994934Sbrian    nargv[arg] = substull(nargv[arg], "PACKETSOUT", pout);
59038629Sbrian    nargv[arg] = subst(nargv[arg], "PEER_ENDDISC",
59138629Sbrian                       mp_Enddisc(bundle->ncp.mp.peer.enddisc.class,
59238629Sbrian                                  bundle->ncp.mp.peer.enddisc.address,
59338629Sbrian                                  bundle->ncp.mp.peer.enddisc.len));
59497360Sbrian    nargv[arg] = substlong(nargv[arg], "PROCESSID", pid);
59594934Sbrian    if (server.cfg.port)
59697360Sbrian      nargv[arg] = substlong(nargv[arg], "SOCKNAME", server.cfg.port);
59794934Sbrian    else
59894934Sbrian      nargv[arg] = subst(nargv[arg], "SOCKNAME", server.cfg.sockname);
59994934Sbrian    nargv[arg] = subst(nargv[arg], "UPTIME", uptime);
60094934Sbrian    nargv[arg] = subst(nargv[arg], "USER", bundle->ncp.mp.peer.authname);
60163484Sbrian    nargv[arg] = subst(nargv[arg], "VERSION", Version);
60238628Sbrian  }
60338628Sbrian  nargv[arg] = NULL;
60438628Sbrian}
60538628Sbrian
60685991Sbrianvoid
60785991Sbriancommand_Free(int argc, char **argv)
60885991Sbrian{
60985991Sbrian  while (argc) {
61085991Sbrian    free(*argv);
61185991Sbrian    argc--;
61285991Sbrian    argv++;
61385991Sbrian  }
61485991Sbrian}
61585991Sbrian
61628536Sbrianstatic int
61731343SbrianShellCommand(struct cmdargs const *arg, int bg)
61810528Samurai{
61910528Samurai  const char *shell;
62047849Sbrian  pid_t shpid, pid;
62120813Sjkh
62218856Ssos#ifdef SHELL_ONLY_INTERACTIVELY
62326911Sbrian  /* we're only allowed to shell when we run ppp interactively */
62436285Sbrian  if (arg->prompt && arg->prompt->owner) {
62536285Sbrian    log_Printf(LogWARN, "Can't start a shell from a network connection\n");
62626516Sbrian    return 1;
62710528Samurai  }
62826911Sbrian#endif
62928679Sbrian
63036285Sbrian  if (arg->argc == arg->argn) {
63136285Sbrian    if (!arg->prompt) {
63236285Sbrian      log_Printf(LogWARN, "Can't start an interactive shell from"
63336285Sbrian                " a config file\n");
63428381Sbrian      return 1;
63536285Sbrian    } else if (arg->prompt->owner) {
63636285Sbrian      log_Printf(LogWARN, "Can't start an interactive shell from"
63736285Sbrian                " a socket connection\n");
63836285Sbrian      return 1;
63928381Sbrian    } else if (bg) {
64036285Sbrian      log_Printf(LogWARN, "Can only start an interactive shell in"
64128679Sbrian		" the foreground mode\n");
64228381Sbrian      return 1;
64328381Sbrian    }
64434536Sbrian  }
64534536Sbrian
64647849Sbrian  pid = getpid();
64728679Sbrian  if ((shpid = fork()) == 0) {
64836285Sbrian    int i, fd;
64918531Sbde
65036285Sbrian    if ((shell = getenv("SHELL")) == 0)
65136285Sbrian      shell = _PATH_BSHELL;
65232017Sbrian
65336285Sbrian    timer_TermService();
65436285Sbrian
65536285Sbrian    if (arg->prompt)
65636285Sbrian      fd = arg->prompt->fd_out;
65736285Sbrian    else if ((fd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
65836285Sbrian      log_Printf(LogALERT, "Failed to open %s: %s\n",
65936285Sbrian                _PATH_DEVNULL, strerror(errno));
66028679Sbrian      exit(1);
66128679Sbrian    }
66249976Sbrian    dup2(fd, STDIN_FILENO);
66349976Sbrian    dup2(fd, STDOUT_FILENO);
66449976Sbrian    dup2(fd, STDERR_FILENO);
66549976Sbrian    for (i = getdtablesize(); i > STDERR_FILENO; i--)
66649976Sbrian      fcntl(i, F_SETFD, 1);
66726516Sbrian
66864802Sbrian#ifndef NOSUID
66955252Sbrian    setuid(ID0realuid());
67064802Sbrian#endif
67136285Sbrian    if (arg->argc > arg->argn) {
67228679Sbrian      /* substitute pseudo args */
67338628Sbrian      char *argv[MAXARGS];
67438628Sbrian      int argc = arg->argc - arg->argn;
67538628Sbrian
67638628Sbrian      if (argc >= sizeof argv / sizeof argv[0]) {
67738628Sbrian        argc = sizeof argv / sizeof argv[0] - 1;
67838628Sbrian        log_Printf(LogWARN, "Truncating shell command to %d args\n", argc);
67931343Sbrian      }
68047849Sbrian      command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 0, pid);
68128679Sbrian      if (bg) {
68228679Sbrian	pid_t p;
68310528Samurai
68428679Sbrian	p = getpid();
68528679Sbrian	if (daemon(1, 1) == -1) {
68697360Sbrian	  log_Printf(LogERROR, "%ld: daemon: %s\n", (long)p, strerror(errno));
68728679Sbrian	  exit(1);
68828679Sbrian	}
68936285Sbrian      } else if (arg->prompt)
69036285Sbrian        printf("ppp: Pausing until %s finishes\n", arg->argv[arg->argn]);
69131343Sbrian      execvp(argv[0], argv);
69230316Sbrian    } else {
69336285Sbrian      if (arg->prompt)
69432017Sbrian        printf("ppp: Pausing until %s finishes\n", shell);
69536285Sbrian      prompt_TtyOldMode(arg->prompt);
69679450Sbrian      execl(shell, shell, (char *)NULL);
69730316Sbrian    }
69820813Sjkh
69940665Sbrian    log_Printf(LogWARN, "exec() of %s failed: %s\n",
70040665Sbrian              arg->argc > arg->argn ? arg->argv[arg->argn] : shell,
70140665Sbrian              strerror(errno));
70249976Sbrian    _exit(255);
70310528Samurai  }
70436285Sbrian
70597360Sbrian  if (shpid == (pid_t)-1)
70636285Sbrian    log_Printf(LogERROR, "Fork failed: %s\n", strerror(errno));
70736285Sbrian  else {
70810528Samurai    int status;
70931343Sbrian    waitpid(shpid, &status, 0);
71010528Samurai  }
71120813Sjkh
71236285Sbrian  if (arg->prompt && !arg->prompt->owner)
71336285Sbrian    prompt_TtyCommandMode(arg->prompt);
71420813Sjkh
71536285Sbrian  return 0;
71610528Samurai}
71710528Samurai
71831343Sbrianstatic int
71931343SbrianBgShellCommand(struct cmdargs const *arg)
72031343Sbrian{
72136285Sbrian  if (arg->argc == arg->argn)
72231343Sbrian    return -1;
72331343Sbrian  return ShellCommand(arg, 1);
72431343Sbrian}
72531343Sbrian
72631343Sbrianstatic int
72731343SbrianFgShellCommand(struct cmdargs const *arg)
72831343Sbrian{
72931343Sbrian  return ShellCommand(arg, 0);
73031343Sbrian}
73131343Sbrian
73258044Sbrianstatic int
73358044SbrianResolvCommand(struct cmdargs const *arg)
73458044Sbrian{
73558044Sbrian  if (arg->argc == arg->argn + 1) {
73658044Sbrian    if (!strcasecmp(arg->argv[arg->argn], "reload"))
73758044Sbrian      ipcp_LoadDNS(&arg->bundle->ncp.ipcp);
73858044Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "restore"))
73958044Sbrian      ipcp_RestoreDNS(&arg->bundle->ncp.ipcp);
74058044Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "rewrite"))
74158044Sbrian      ipcp_WriteDNS(&arg->bundle->ncp.ipcp);
74258044Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "readonly"))
74358044Sbrian      arg->bundle->ncp.ipcp.ns.writable = 0;
74458044Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "writable"))
74558044Sbrian      arg->bundle->ncp.ipcp.ns.writable = 1;
74658044Sbrian    else
74758044Sbrian      return -1;
74858044Sbrian
74958044Sbrian    return 0;
75058044Sbrian  }
75158044Sbrian
75258044Sbrian  return -1;
75358044Sbrian}
75458044Sbrian
75550059Sbrian#ifndef NONAT
75658867Sbrianstatic struct cmdtab const NatCommands[] =
75740561Sbrian{
75850059Sbrian  {"addr", NULL, nat_RedirectAddr, LOCAL_AUTH,
75950059Sbrian   "static address translation", "nat addr [addr_local addr_alias]"},
76058867Sbrian  {"deny_incoming", NULL, NatOption, LOCAL_AUTH,
76150059Sbrian   "stop incoming connections", "nat deny_incoming yes|no",
76240561Sbrian   (const void *) PKT_ALIAS_DENY_INCOMING},
76358867Sbrian  {"enable", NULL, NatEnable, LOCAL_AUTH,
76450059Sbrian   "enable NAT", "nat enable yes|no"},
76558867Sbrian  {"log", NULL, NatOption, LOCAL_AUTH,
76650059Sbrian   "log NAT link creation", "nat log yes|no",
76740561Sbrian   (const void *) PKT_ALIAS_LOG},
76850059Sbrian  {"port", NULL, nat_RedirectPort, LOCAL_AUTH, "port redirection",
76950059Sbrian   "nat port proto localaddr:port[-port] aliasport[-aliasport]"},
77079433Sbrian  {"proto", NULL, nat_RedirectProto, LOCAL_AUTH, "protocol redirection",
77179433Sbrian   "nat proto proto localIP [publicIP [remoteIP]]"},
77250059Sbrian  {"proxy", NULL, nat_ProxyRule, LOCAL_AUTH,
77350059Sbrian   "proxy control", "nat proxy server host[:port] ..."},
77481033Sbrian#ifndef NO_FW_PUNCH
77581033Sbrian  {"punch_fw", NULL, nat_PunchFW, LOCAL_AUTH,
77681033Sbrian   "firewall control", "nat punch_fw [base count]"},
77781033Sbrian#endif
778120372Smarcus  {"skinny_port", NULL, nat_SkinnyPort, LOCAL_AUTH,
779120372Smarcus   "TCP port used by Skinny Station protocol", "nat skinny_port [port]"},
78058867Sbrian  {"same_ports", NULL, NatOption, LOCAL_AUTH,
78150059Sbrian   "try to leave port numbers unchanged", "nat same_ports yes|no",
78240561Sbrian   (const void *) PKT_ALIAS_SAME_PORTS},
78358867Sbrian  {"target", NULL, nat_SetTarget, LOCAL_AUTH,
78458867Sbrian   "Default address for incoming connections", "nat target addr" },
78558867Sbrian  {"unregistered_only", NULL, NatOption, LOCAL_AUTH,
78650059Sbrian   "translate unregistered (private) IP address space only",
78750059Sbrian   "nat unregistered_only yes|no",
78840561Sbrian   (const void *) PKT_ALIAS_UNREGISTERED_ONLY},
78958867Sbrian  {"use_sockets", NULL, NatOption, LOCAL_AUTH,
79050059Sbrian   "allocate host sockets", "nat use_sockets yes|no",
79140561Sbrian   (const void *) PKT_ALIAS_USE_SOCKETS},
79240561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
79358867Sbrian   "Display this message", "nat help|? [command]", NatCommands},
79440561Sbrian  {NULL, NULL, NULL},
79540561Sbrian};
79640561Sbrian#endif
79740561Sbrian
79840561Sbrianstatic struct cmdtab const AllowCommands[] = {
79940561Sbrian  {"modes", "mode", AllowModes, LOCAL_AUTH,
80040561Sbrian  "Only allow certain ppp modes", "allow modes mode..."},
80140561Sbrian  {"users", "user", AllowUsers, LOCAL_AUTH,
80240561Sbrian  "Only allow ppp access to certain users", "allow users logname..."},
80340561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
80440561Sbrian  "Display this message", "allow help|? [command]", AllowCommands},
80540561Sbrian  {NULL, NULL, NULL},
80640561Sbrian};
80740561Sbrian
80840561Sbrianstatic struct cmdtab const IfaceCommands[] =
80940561Sbrian{
81040561Sbrian  {"add", NULL, IfaceAddCommand, LOCAL_AUTH,
81140561Sbrian   "Add iface address", "iface add addr[/bits| mask] peer", NULL},
81240561Sbrian  {NULL, "add!", IfaceAddCommand, LOCAL_AUTH,
81340561Sbrian   "Add or change an iface address", "iface add! addr[/bits| mask] peer",
81440561Sbrian   (void *)1},
81540561Sbrian  {"clear", NULL, IfaceClearCommand, LOCAL_AUTH,
81681634Sbrian   "Clear iface address(es)", "iface clear [INET | INET6]"},
81740561Sbrian  {"delete", "rm", IfaceDeleteCommand, LOCAL_AUTH,
81840561Sbrian   "Delete iface address", "iface delete addr", NULL},
81940561Sbrian  {NULL, "rm!", IfaceDeleteCommand, LOCAL_AUTH,
82040561Sbrian   "Delete iface address", "iface delete addr", (void *)1},
82140561Sbrian  {NULL, "delete!", IfaceDeleteCommand, LOCAL_AUTH,
82240561Sbrian   "Delete iface address", "iface delete addr", (void *)1},
82340561Sbrian  {"show", NULL, iface_Show, LOCAL_AUTH,
82440561Sbrian   "Show iface address(es)", "iface show"},
82540561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
82650059Sbrian   "Display this message", "nat help|? [command]", IfaceCommands},
82740561Sbrian  {NULL, NULL, NULL},
82840561Sbrian};
82940561Sbrian
83030715Sbrianstatic struct cmdtab const Commands[] = {
83136285Sbrian  {"accept", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
83228679Sbrian  "accept option request", "accept option .."},
83328679Sbrian  {"add", NULL, AddCommand, LOCAL_AUTH,
83432109Sbrian  "add route", "add dest mask gateway", NULL},
83536285Sbrian  {NULL, "add!", AddCommand, LOCAL_AUTH,
83632109Sbrian  "add or change route", "add! dest mask gateway", (void *)1},
83740561Sbrian  {"allow", "auth", RunListCommand, LOCAL_AUTH,
83840561Sbrian  "Allow ppp access", "allow users|modes ....", AllowCommands},
83928679Sbrian  {"bg", "!bg", BgShellCommand, LOCAL_AUTH,
84031372Sbrian  "Run a background command", "[!]bg command"},
84136934Sbrian  {"clear", NULL, ClearCommand, LOCAL_AUTH | LOCAL_CX_OPT,
84246686Sbrian  "Clear throughput statistics",
84381634Sbrian  "clear ipcp|ipv6cp|physical [current|overall|peak]..."},
84436285Sbrian  {"clone", NULL, CloneCommand, LOCAL_AUTH | LOCAL_CX,
84536285Sbrian  "Clone a link", "clone newname..."},
84636285Sbrian  {"close", NULL, CloseCommand, LOCAL_AUTH | LOCAL_CX_OPT,
84736285Sbrian  "Close an FSM", "close [lcp|ccp]"},
84828679Sbrian  {"delete", NULL, DeleteCommand, LOCAL_AUTH,
84932109Sbrian  "delete route", "delete dest", NULL},
85036285Sbrian  {NULL, "delete!", DeleteCommand, LOCAL_AUTH,
85132109Sbrian  "delete a route if it exists", "delete! dest", (void *)1},
85236285Sbrian  {"deny", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
85328679Sbrian  "Deny option request", "deny option .."},
85436285Sbrian  {"dial", "call", DialCommand, LOCAL_AUTH | LOCAL_CX_OPT,
85540797Sbrian  "Dial and login", "dial|call [system ...]", NULL},
85636285Sbrian  {"disable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
85728679Sbrian  "Disable option", "disable option .."},
85836285Sbrian  {"down", NULL, DownCommand, LOCAL_AUTH | LOCAL_CX_OPT,
85946686Sbrian  "Generate a down event", "down [ccp|lcp]"},
86036285Sbrian  {"enable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
86128679Sbrian  "Enable option", "enable option .."},
86263484Sbrian  {"ident", NULL, IdentCommand, LOCAL_AUTH | LOCAL_CX,
86363484Sbrian  "Set the link identity", "ident text..."},
86440561Sbrian  {"iface", "interface", RunListCommand, LOCAL_AUTH,
86540561Sbrian  "interface control", "iface option ...", IfaceCommands},
86636285Sbrian  {"link", "datalink", LinkCommand, LOCAL_AUTH,
86736285Sbrian  "Link specific commands", "link name command ..."},
86837008Sbrian  {"load", NULL, LoadCommand, LOCAL_AUTH | LOCAL_CX_OPT,
86940797Sbrian  "Load settings", "load [system ...]"},
87085991Sbrian  {"log", NULL, LogCommand, LOCAL_AUTH | LOCAL_CX_OPT,
87185991Sbrian  "log information", "log word ..."},
87250059Sbrian#ifndef NONAT
87350059Sbrian  {"nat", "alias", RunListCommand, LOCAL_AUTH,
87458867Sbrian  "NAT control", "nat option yes|no", NatCommands},
87550059Sbrian#endif
87636285Sbrian  {"open", NULL, OpenCommand, LOCAL_AUTH | LOCAL_CX_OPT,
87737955Sbrian  "Open an FSM", "open! [lcp|ccp|ipcp]", (void *)1},
87836285Sbrian  {"passwd", NULL, PasswdCommand, LOCAL_NO_AUTH,
87936285Sbrian  "Password for manipulation", "passwd LocalPassword"},
88036285Sbrian  {"quit", "bye", QuitCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
88136285Sbrian  "Quit PPP program", "quit|bye [all]"},
88236285Sbrian  {"remove", "rm", RemoveCommand, LOCAL_AUTH | LOCAL_CX,
88336285Sbrian  "Remove a link", "remove"},
88436285Sbrian  {"rename", "mv", RenameCommand, LOCAL_AUTH | LOCAL_CX,
88536285Sbrian  "Rename a link", "rename name"},
88658044Sbrian  {"resolv", NULL, ResolvCommand, LOCAL_AUTH,
88758044Sbrian  "Manipulate resolv.conf", "resolv readonly|reload|restore|rewrite|writable"},
88828679Sbrian  {"save", NULL, SaveCommand, LOCAL_AUTH,
88928679Sbrian  "Save settings", "save"},
89063484Sbrian  {"sendident", NULL, SendIdentification, LOCAL_AUTH | LOCAL_CX,
89163484Sbrian  "Transmit the link identity", "sendident"},
89236285Sbrian  {"set", "setup", SetCommand, LOCAL_AUTH | LOCAL_CX_OPT,
89328679Sbrian  "Set parameters", "set[up] var value"},
89428679Sbrian  {"shell", "!", FgShellCommand, LOCAL_AUTH,
89528679Sbrian  "Run a subshell", "shell|! [sh command]"},
89636285Sbrian  {"show", NULL, ShowCommand, LOCAL_AUTH | LOCAL_CX_OPT,
89731372Sbrian  "Show status and stats", "show var"},
89836285Sbrian  {"term", NULL, TerminalCommand, LOCAL_AUTH | LOCAL_CX,
89931372Sbrian  "Enter terminal mode", "term"},
90028679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
90131343Sbrian  "Display this message", "help|? [command]", Commands},
90228679Sbrian  {NULL, NULL, NULL},
9036059Samurai};
9046059Samurai
90528536Sbrianstatic int
90631343SbrianShowEscape(struct cmdargs const *arg)
9076059Samurai{
90836285Sbrian  if (arg->cx->physical->async.cfg.EscMap[32]) {
90936285Sbrian    int code, bit;
91036285Sbrian    const char *sep = "";
9116059Samurai
91226516Sbrian    for (code = 0; code < 32; code++)
91336285Sbrian      if (arg->cx->physical->async.cfg.EscMap[code])
91428679Sbrian	for (bit = 0; bit < 8; bit++)
91536285Sbrian	  if (arg->cx->physical->async.cfg.EscMap[code] & (1 << bit)) {
91636285Sbrian	    prompt_Printf(arg->prompt, "%s0x%02x", sep, (code << 3) + bit);
91736285Sbrian            sep = ", ";
91836285Sbrian          }
91936285Sbrian    prompt_Printf(arg->prompt, "\n");
9206059Samurai  }
92131077Sbrian  return 0;
9226059Samurai}
9236059Samurai
92428679Sbrianstatic int
92536285SbrianShowTimerList(struct cmdargs const *arg)
9266059Samurai{
92736285Sbrian  timer_Show(0, arg->prompt);
92831077Sbrian  return 0;
9296059Samurai}
9306059Samurai
93128679Sbrianstatic int
93231343SbrianShowStopped(struct cmdargs const *arg)
93328327Sbrian{
93436285Sbrian  prompt_Printf(arg->prompt, " Stopped Timer:  LCP: ");
93536285Sbrian  if (!arg->cx->physical->link.lcp.fsm.StoppedTimer.load)
93636285Sbrian    prompt_Printf(arg->prompt, "Disabled");
93728327Sbrian  else
93836285Sbrian    prompt_Printf(arg->prompt, "%ld secs",
93936285Sbrian                  arg->cx->physical->link.lcp.fsm.StoppedTimer.load / SECTICKS);
94028461Sbrian
94136285Sbrian  prompt_Printf(arg->prompt, ", CCP: ");
94236285Sbrian  if (!arg->cx->physical->link.ccp.fsm.StoppedTimer.load)
94336285Sbrian    prompt_Printf(arg->prompt, "Disabled");
94428461Sbrian  else
94536285Sbrian    prompt_Printf(arg->prompt, "%ld secs",
94636285Sbrian                  arg->cx->physical->link.ccp.fsm.StoppedTimer.load / SECTICKS);
94728461Sbrian
94836285Sbrian  prompt_Printf(arg->prompt, "\n");
94928461Sbrian
95031077Sbrian  return 0;
95128327Sbrian}
95228327Sbrian
95328679Sbrianstatic int
95431343SbrianShowVersion(struct cmdargs const *arg)
9556059Samurai{
95651026Sbrian  prompt_Printf(arg->prompt, "PPP Version %s - %s\n", Version, __DATE__);
95731077Sbrian  return 0;
9586059Samurai}
9596059Samurai
96028679Sbrianstatic int
96136285SbrianShowProtocolStats(struct cmdargs const *arg)
96226326Sbrian{
96336285Sbrian  struct link *l = command_ChooseLink(arg);
96426326Sbrian
96536285Sbrian  prompt_Printf(arg->prompt, "%s:\n", l->name);
96636285Sbrian  link_ReportProtocolStatus(l, arg->prompt);
96731077Sbrian  return 0;
96826326Sbrian}
96926326Sbrian
97030715Sbrianstatic struct cmdtab const ShowCommands[] = {
97136285Sbrian  {"bundle", NULL, bundle_ShowStatus, LOCAL_AUTH,
97236285Sbrian  "bundle details", "show bundle"},
97336285Sbrian  {"ccp", NULL, ccp_ReportStatus, LOCAL_AUTH | LOCAL_CX_OPT,
97436285Sbrian  "CCP status", "show cpp"},
97536285Sbrian  {"compress", NULL, sl_Show, LOCAL_AUTH,
97636285Sbrian  "VJ compression stats", "show compress"},
97736285Sbrian  {"escape", NULL, ShowEscape, LOCAL_AUTH | LOCAL_CX,
97836285Sbrian  "escape characters", "show escape"},
97936285Sbrian  {"filter", NULL, filter_Show, LOCAL_AUTH,
98036285Sbrian  "packet filters", "show filter [in|out|dial|alive]"},
98136285Sbrian  {"hdlc", NULL, hdlc_ReportStatus, LOCAL_AUTH | LOCAL_CX,
98236285Sbrian  "HDLC errors", "show hdlc"},
98340561Sbrian  {"iface", "interface", iface_Show, LOCAL_AUTH,
98440561Sbrian  "Interface status", "show iface"},
98536285Sbrian  {"ipcp", NULL, ipcp_Show, LOCAL_AUTH,
98636285Sbrian  "IPCP status", "show ipcp"},
98781634Sbrian#ifndef NOINET6
98881634Sbrian  {"ipv6cp", NULL, ipv6cp_Show, LOCAL_AUTH,
98981634Sbrian  "IPV6CP status", "show ipv6cp"},
99081634Sbrian#endif
99147211Sbrian  {"layers", NULL, link_ShowLayers, LOCAL_AUTH | LOCAL_CX_OPT,
99247211Sbrian  "Protocol layers", "show layers"},
99336285Sbrian  {"lcp", NULL, lcp_ReportStatus, LOCAL_AUTH | LOCAL_CX,
99436285Sbrian  "LCP status", "show lcp"},
99536285Sbrian  {"link", "datalink", datalink_Show, LOCAL_AUTH | LOCAL_CX,
99636285Sbrian  "(high-level) link info", "show link"},
99736285Sbrian  {"links", NULL, bundle_ShowLinks, LOCAL_AUTH,
99836285Sbrian  "available link names", "show links"},
99936285Sbrian  {"log", NULL, log_ShowLevel, LOCAL_AUTH,
100036285Sbrian  "log levels", "show log"},
100136285Sbrian  {"mem", NULL, mbuf_Show, LOCAL_AUTH,
100236285Sbrian  "mbuf allocations", "show mem"},
100381634Sbrian  {"ncp", NULL, ncp_Show, LOCAL_AUTH,
100481634Sbrian  "NCP status", "show ncp"},
100546686Sbrian  {"physical", NULL, physical_ShowStatus, LOCAL_AUTH | LOCAL_CX,
100646686Sbrian  "(low-level) link info", "show physical"},
100736285Sbrian  {"mp", "multilink", mp_ShowStatus, LOCAL_AUTH,
100836285Sbrian  "multilink setup", "show mp"},
100936285Sbrian  {"proto", NULL, ShowProtocolStats, LOCAL_AUTH | LOCAL_CX_OPT,
101036285Sbrian  "protocol summary", "show proto"},
101136285Sbrian  {"route", NULL, route_Show, LOCAL_AUTH,
101236285Sbrian  "routing table", "show route"},
101336285Sbrian  {"stopped", NULL, ShowStopped, LOCAL_AUTH | LOCAL_CX,
101436285Sbrian  "STOPPED timeout", "show stopped"},
101536285Sbrian  {"timers", NULL, ShowTimerList, LOCAL_AUTH,
101636285Sbrian  "alarm timers", "show timers"},
101728679Sbrian  {"version", NULL, ShowVersion, LOCAL_NO_AUTH | LOCAL_AUTH,
101836285Sbrian  "version string", "show version"},
101936285Sbrian  {"who", NULL, log_ShowWho, LOCAL_AUTH,
102036285Sbrian  "client list", "show who"},
102128679Sbrian  {"help", "?", HelpCommand, LOCAL_NO_AUTH | LOCAL_AUTH,
102231343Sbrian  "Display this message", "show help|? [command]", ShowCommands},
102328679Sbrian  {NULL, NULL, NULL},
10246059Samurai};
10256059Samurai
102630715Sbrianstatic struct cmdtab const *
102731343SbrianFindCommand(struct cmdtab const *cmds, const char *str, int *pmatch)
10286059Samurai{
102926516Sbrian  int nmatch;
103026516Sbrian  int len;
103128679Sbrian  struct cmdtab const *found;
10326059Samurai
103326516Sbrian  found = NULL;
103426516Sbrian  len = strlen(str);
103526516Sbrian  nmatch = 0;
10366059Samurai  while (cmds->func) {
103725566Sbrian    if (cmds->name && strncasecmp(str, cmds->name, len) == 0) {
103826516Sbrian      if (cmds->name[len] == '\0') {
103928679Sbrian	*pmatch = 1;
104028679Sbrian	return cmds;
104126516Sbrian      }
10426059Samurai      nmatch++;
10436059Samurai      found = cmds;
104428679Sbrian    } else if (cmds->alias && strncasecmp(str, cmds->alias, len) == 0) {
104526516Sbrian      if (cmds->alias[len] == '\0') {
104628679Sbrian	*pmatch = 1;
104728679Sbrian	return cmds;
104826516Sbrian      }
10496059Samurai      nmatch++;
10506059Samurai      found = cmds;
10516059Samurai    }
10526059Samurai    cmds++;
10536059Samurai  }
10546059Samurai  *pmatch = nmatch;
105526516Sbrian  return found;
10566059Samurai}
10576059Samurai
105836285Sbrianstatic const char *
105936285SbrianmkPrefix(int argc, char const *const *argv, char *tgt, int sz)
106036285Sbrian{
106136285Sbrian  int f, tlen, len;
106236285Sbrian
106336285Sbrian  tlen = 0;
106436285Sbrian  for (f = 0; f < argc && tlen < sz - 2; f++) {
106536285Sbrian    if (f)
106636285Sbrian      tgt[tlen++] = ' ';
106736285Sbrian    len = strlen(argv[f]);
106836285Sbrian    if (len > sz - tlen - 1)
106936285Sbrian      len = sz - tlen - 1;
107036285Sbrian    strncpy(tgt+tlen, argv[f], len);
107136285Sbrian    tlen += len;
107236285Sbrian  }
107336285Sbrian  tgt[tlen] = '\0';
107436285Sbrian  return tgt;
107536285Sbrian}
107636285Sbrian
107730715Sbrianstatic int
107836285SbrianFindExec(struct bundle *bundle, struct cmdtab const *cmds, int argc, int argn,
107936285Sbrian         char const *const *argv, struct prompt *prompt, struct datalink *cx)
10806059Samurai{
108128679Sbrian  struct cmdtab const *cmd;
10826059Samurai  int val = 1;
10836059Samurai  int nmatch;
108431343Sbrian  struct cmdargs arg;
108536285Sbrian  char prefix[100];
10866059Samurai
108736285Sbrian  cmd = FindCommand(cmds, argv[argn], &nmatch);
10886059Samurai  if (nmatch > 1)
108936285Sbrian    log_Printf(LogWARN, "%s: Ambiguous command\n",
109036285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix));
109136285Sbrian  else if (cmd && (!prompt || (cmd->lauth & prompt->auth))) {
109236285Sbrian    if ((cmd->lauth & LOCAL_CX) && !cx)
109336285Sbrian      /* We've got no context, but we require it */
109436285Sbrian      cx = bundle2datalink(bundle, NULL);
109536285Sbrian
109636285Sbrian    if ((cmd->lauth & LOCAL_CX) && !cx)
109736285Sbrian      log_Printf(LogWARN, "%s: No context (use the `link' command)\n",
109836285Sbrian                mkPrefix(argn+1, argv, prefix, sizeof prefix));
109936285Sbrian    else {
110036285Sbrian      if (cx && !(cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
110136285Sbrian        log_Printf(LogWARN, "%s: Redundant context (%s) ignored\n",
110236285Sbrian                  mkPrefix(argn+1, argv, prefix, sizeof prefix), cx->name);
110336285Sbrian        cx = NULL;
110436285Sbrian      }
110536285Sbrian      arg.cmdtab = cmds;
110636285Sbrian      arg.cmd = cmd;
110736285Sbrian      arg.argc = argc;
110836285Sbrian      arg.argn = argn+1;
110936285Sbrian      arg.argv = argv;
111036285Sbrian      arg.bundle = bundle;
111136285Sbrian      arg.cx = cx;
111236285Sbrian      arg.prompt = prompt;
111336285Sbrian      val = (*cmd->func) (&arg);
111436285Sbrian    }
111531343Sbrian  } else
111636285Sbrian    log_Printf(LogWARN, "%s: Invalid command\n",
111736285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix));
111826516Sbrian
111926516Sbrian  if (val == -1)
112095258Sdes    log_Printf(LogWARN, "usage: %s\n", cmd->syntax);
112128679Sbrian  else if (val)
112236285Sbrian    log_Printf(LogWARN, "%s: Failed %d\n",
112336285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix), val);
112426516Sbrian
112526516Sbrian  return val;
11266059Samurai}
11276059Samurai
112837009Sbrianint
112958045Sbriancommand_Expand_Interpret(char *buff, int nb, char *argv[MAXARGS], int offset)
113058045Sbrian{
113158045Sbrian  char buff2[LINE_LEN-offset];
113258045Sbrian
113358045Sbrian  InterpretArg(buff, buff2);
113458045Sbrian  strncpy(buff, buff2, LINE_LEN - offset - 1);
113558045Sbrian  buff[LINE_LEN - offset - 1] = '\0';
113658045Sbrian
113758045Sbrian  return command_Interpret(buff, nb, argv);
113858045Sbrian}
113958045Sbrian
114058045Sbrianint
114137009Sbriancommand_Interpret(char *buff, int nb, char *argv[MAXARGS])
11426059Samurai{
11436059Samurai  char *cp;
11446059Samurai
11456059Samurai  if (nb > 0) {
11466059Samurai    cp = buff + strcspn(buff, "\r\n");
11476059Samurai    if (cp)
11486059Samurai      *cp = '\0';
114955145Sbrian    return MakeArgs(buff, argv, MAXARGS, PARSE_REDUCE);
115037009Sbrian  }
115137009Sbrian  return 0;
115231121Sbrian}
11536059Samurai
115431822Sbrianstatic int
115531822Sbrianarghidden(int argc, char const *const *argv, int n)
115631822Sbrian{
115731822Sbrian  /* Is arg n of the given command to be hidden from the log ? */
115831828Sbrian
115931828Sbrian  /* set authkey xxxxx */
116031828Sbrian  /* set key xxxxx */
116131822Sbrian  if (n == 2 && !strncasecmp(argv[0], "se", 2) &&
116231822Sbrian      (!strncasecmp(argv[1], "authk", 5) || !strncasecmp(argv[1], "ke", 2)))
116331822Sbrian    return 1;
116431822Sbrian
116531828Sbrian  /* passwd xxxxx */
116631828Sbrian  if (n == 1 && !strncasecmp(argv[0], "p", 1))
116731828Sbrian    return 1;
116831828Sbrian
116936285Sbrian  /* set server port xxxxx .... */
117036285Sbrian  if (n == 3 && !strncasecmp(argv[0], "se", 2) &&
117136285Sbrian      !strncasecmp(argv[1], "se", 2))
117236285Sbrian    return 1;
117336285Sbrian
117431822Sbrian  return 0;
117531822Sbrian}
117631822Sbrian
117731121Sbrianvoid
117836285Sbriancommand_Run(struct bundle *bundle, int argc, char const *const *argv,
117937008Sbrian           struct prompt *prompt, const char *label, struct datalink *cx)
118031121Sbrian{
118131156Sbrian  if (argc > 0) {
118236285Sbrian    if (log_IsKept(LogCOMMAND)) {
118347844Sbrian      char buf[LINE_LEN];
118431156Sbrian      int f, n;
118531156Sbrian
118631156Sbrian      if (label) {
118731962Sbrian        strncpy(buf, label, sizeof buf - 3);
118831962Sbrian        buf[sizeof buf - 3] = '\0';
118931156Sbrian        strcat(buf, ": ");
119047844Sbrian        n = strlen(buf);
119147844Sbrian      } else {
119247844Sbrian        *buf = '\0';
119347844Sbrian        n = 0;
119431156Sbrian      }
119547844Sbrian      buf[sizeof buf - 1] = '\0';	/* In case we run out of room in buf */
119647844Sbrian
119731156Sbrian      for (f = 0; f < argc; f++) {
119831962Sbrian        if (n < sizeof buf - 1 && f)
119931156Sbrian          buf[n++] = ' ';
120031822Sbrian        if (arghidden(argc, argv, f))
120136285Sbrian          strncpy(buf+n, "********", sizeof buf - n - 1);
120231822Sbrian        else
120331962Sbrian          strncpy(buf+n, argv[f], sizeof buf - n - 1);
120431156Sbrian        n += strlen(buf+n);
120531156Sbrian      }
120636285Sbrian      log_Printf(LogCOMMAND, "%s\n", buf);
120731156Sbrian    }
120837008Sbrian    FindExec(bundle, Commands, argc, 0, argv, prompt, cx);
120931156Sbrian  }
12106059Samurai}
12116059Samurai
121254914Sbrianint
121336285Sbriancommand_Decode(struct bundle *bundle, char *buff, int nb, struct prompt *prompt,
121436285Sbrian              const char *label)
121531121Sbrian{
121631121Sbrian  int argc;
121737009Sbrian  char *argv[MAXARGS];
121831121Sbrian
121958045Sbrian  if ((argc = command_Expand_Interpret(buff, nb, argv, 0)) < 0)
122054914Sbrian    return 0;
122154914Sbrian
122237008Sbrian  command_Run(bundle, argc, (char const *const *)argv, prompt, label, NULL);
122354914Sbrian  return 1;
122431121Sbrian}
122531121Sbrian
12266059Samuraistatic int
122731343SbrianShowCommand(struct cmdargs const *arg)
12286059Samurai{
122936285Sbrian  if (!arg->prompt)
123036285Sbrian    log_Printf(LogWARN, "show: Cannot show without a prompt\n");
123136285Sbrian  else if (arg->argc > arg->argn)
123236285Sbrian    FindExec(arg->bundle, ShowCommands, arg->argc, arg->argn, arg->argv,
123336285Sbrian             arg->prompt, arg->cx);
12346059Samurai  else
123536285Sbrian    prompt_Printf(arg->prompt, "Use ``show ?'' to get a list.\n");
123626516Sbrian
123726516Sbrian  return 0;
12386059Samurai}
12396059Samurai
12406059Samuraistatic int
124131343SbrianTerminalCommand(struct cmdargs const *arg)
12426059Samurai{
124336285Sbrian  if (!arg->prompt) {
124436285Sbrian    log_Printf(LogWARN, "term: Need a prompt\n");
124526516Sbrian    return 1;
12466059Samurai  }
124736285Sbrian
124836285Sbrian  if (arg->cx->physical->link.lcp.fsm.state > ST_CLOSED) {
124936285Sbrian    prompt_Printf(arg->prompt, "LCP state is [%s]\n",
125036285Sbrian                  State2Nam(arg->cx->physical->link.lcp.fsm.state));
125136285Sbrian    return 1;
12526059Samurai  }
125336285Sbrian
125436285Sbrian  datalink_Up(arg->cx, 0, 0);
125536285Sbrian  prompt_TtyTermMode(arg->prompt, arg->cx);
125636285Sbrian  return 0;
12576059Samurai}
12586059Samurai
12596059Samuraistatic int
126031343SbrianQuitCommand(struct cmdargs const *arg)
12616059Samurai{
126236285Sbrian  if (!arg->prompt || prompt_IsController(arg->prompt) ||
126336285Sbrian      (arg->argc > arg->argn && !strcasecmp(arg->argv[arg->argn], "all") &&
126436285Sbrian       (arg->prompt->auth & LOCAL_AUTH)))
126536285Sbrian    Cleanup(EX_NORMAL);
126636285Sbrian  if (arg->prompt)
126736285Sbrian    prompt_Destroy(arg->prompt, 1);
126826516Sbrian
126926516Sbrian  return 0;
12706059Samurai}
12716059Samurai
12726059Samuraistatic int
127336285SbrianOpenCommand(struct cmdargs const *arg)
12746059Samurai{
127537160Sbrian  if (arg->argc == arg->argn)
127637993Sbrian    bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1);
127737160Sbrian  else if (arg->argc == arg->argn + 1) {
127837160Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp")) {
127937385Sbrian      struct datalink *cx = arg->cx ?
128037385Sbrian        arg->cx : bundle2datalink(arg->bundle, NULL);
128137385Sbrian      if (cx) {
128237385Sbrian        if (cx->physical->link.lcp.fsm.state == ST_OPENED)
128337385Sbrian          fsm_Reopen(&cx->physical->link.lcp.fsm);
128437160Sbrian        else
128537993Sbrian          bundle_Open(arg->bundle, cx->name, PHYS_ALL, 1);
128637160Sbrian      } else
128737160Sbrian        log_Printf(LogWARN, "open lcp: You must specify a link\n");
128837160Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) {
128937160Sbrian      struct fsm *fp;
12906059Samurai
129137210Sbrian      fp = &command_ChooseLink(arg)->ccp.fsm;
129237160Sbrian      if (fp->link->lcp.fsm.state != ST_OPENED)
129337160Sbrian        log_Printf(LogWARN, "open: LCP must be open before opening CCP\n");
129437160Sbrian      else if (fp->state == ST_OPENED)
129537160Sbrian        fsm_Reopen(fp);
129637160Sbrian      else {
129737160Sbrian        fp->open_mode = 0;	/* Not passive any more */
129837160Sbrian        if (fp->state == ST_STOPPED) {
129937160Sbrian          fsm_Down(fp);
130037160Sbrian          fsm_Up(fp);
130137160Sbrian        } else {
130237160Sbrian          fsm_Up(fp);
130337160Sbrian          fsm_Open(fp);
130437160Sbrian        }
130536285Sbrian      }
130637160Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ipcp")) {
130737160Sbrian      if (arg->cx)
130837160Sbrian        log_Printf(LogWARN, "open ipcp: You need not specify a link\n");
130937160Sbrian      if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED)
131037160Sbrian        fsm_Reopen(&arg->bundle->ncp.ipcp.fsm);
131137160Sbrian      else
131237993Sbrian        bundle_Open(arg->bundle, NULL, PHYS_ALL, 1);
131337160Sbrian    } else
131437160Sbrian      return -1;
131536285Sbrian  } else
131636285Sbrian    return -1;
131736285Sbrian
131826516Sbrian  return 0;
13196059Samurai}
13206059Samurai
132125067Sbrianstatic int
132236285SbrianCloseCommand(struct cmdargs const *arg)
13236059Samurai{
132437007Sbrian  if (arg->argc == arg->argn)
132537007Sbrian    bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_STAYDOWN);
132637007Sbrian  else if (arg->argc == arg->argn + 1) {
132737007Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp"))
132837007Sbrian      bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_LCP);
132937007Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "ccp") ||
133037007Sbrian             !strcasecmp(arg->argv[arg->argn], "ccp!")) {
133137007Sbrian      struct fsm *fp;
13326059Samurai
133337210Sbrian      fp = &command_ChooseLink(arg)->ccp.fsm;
133437007Sbrian      if (fp->state == ST_OPENED) {
133537007Sbrian        fsm_Close(fp);
133637007Sbrian        if (arg->argv[arg->argn][3] == '!')
133737007Sbrian          fp->open_mode = 0;		/* Stay ST_CLOSED */
133837007Sbrian        else
133937007Sbrian          fp->open_mode = OPEN_PASSIVE;	/* Wait for the peer to start */
134037007Sbrian      }
134137007Sbrian    } else
134236285Sbrian      return -1;
134336285Sbrian  } else
134436285Sbrian    return -1;
134536285Sbrian
134636285Sbrian  return 0;
13476059Samurai}
13486059Samurai
134925067Sbrianstatic int
135036285SbrianDownCommand(struct cmdargs const *arg)
135111336Samurai{
135237018Sbrian  if (arg->argc == arg->argn) {
135337018Sbrian      if (arg->cx)
135437018Sbrian        datalink_Down(arg->cx, CLOSE_STAYDOWN);
135537018Sbrian      else
135637018Sbrian        bundle_Down(arg->bundle, CLOSE_STAYDOWN);
135737018Sbrian  } else if (arg->argc == arg->argn + 1) {
135837018Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp")) {
135937018Sbrian      if (arg->cx)
136037018Sbrian        datalink_Down(arg->cx, CLOSE_LCP);
136137018Sbrian      else
136237018Sbrian        bundle_Down(arg->bundle, CLOSE_LCP);
136337018Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) {
136437018Sbrian      struct fsm *fp = arg->cx ? &arg->cx->physical->link.ccp.fsm :
136537018Sbrian                                 &arg->bundle->ncp.mp.link.ccp.fsm;
136637060Sbrian      fsm2initial(fp);
136737018Sbrian    } else
136837018Sbrian      return -1;
136936285Sbrian  } else
137036285Sbrian    return -1;
137136285Sbrian
137236285Sbrian  return 0;
137325067Sbrian}
137425067Sbrian
137525067Sbrianstatic int
137636285SbrianSetModemSpeed(struct cmdargs const *arg)
137725067Sbrian{
137836285Sbrian  long speed;
137936285Sbrian  char *end;
138011336Samurai
138136285Sbrian  if (arg->argc > arg->argn && *arg->argv[arg->argn]) {
138236285Sbrian    if (arg->argc > arg->argn+1) {
138354917Sbrian      log_Printf(LogWARN, "SetModemSpeed: Too many arguments\n");
138436285Sbrian      return -1;
138511336Samurai    }
138636285Sbrian    if (strcasecmp(arg->argv[arg->argn], "sync") == 0) {
138736285Sbrian      physical_SetSync(arg->cx->physical);
138836285Sbrian      return 0;
138936285Sbrian    }
139036285Sbrian    end = NULL;
139136285Sbrian    speed = strtol(arg->argv[arg->argn], &end, 10);
139236285Sbrian    if (*end) {
139336285Sbrian      log_Printf(LogWARN, "SetModemSpeed: Bad argument \"%s\"",
139436285Sbrian                arg->argv[arg->argn]);
139536285Sbrian      return -1;
139636285Sbrian    }
139736285Sbrian    if (physical_SetSpeed(arg->cx->physical, speed))
139836285Sbrian      return 0;
139936285Sbrian    log_Printf(LogWARN, "%s: Invalid speed\n", arg->argv[arg->argn]);
140036285Sbrian  } else
140136285Sbrian    log_Printf(LogWARN, "SetModemSpeed: No speed specified\n");
140224939Sbrian
140326516Sbrian  return -1;
140411336Samurai}
140511336Samurai
140625067Sbrianstatic int
140731343SbrianSetStoppedTimeout(struct cmdargs const *arg)
140828327Sbrian{
140936285Sbrian  struct link *l = &arg->cx->physical->link;
141036285Sbrian
141136285Sbrian  l->lcp.fsm.StoppedTimer.load = 0;
141236285Sbrian  l->ccp.fsm.StoppedTimer.load = 0;
141336285Sbrian  if (arg->argc <= arg->argn+2) {
141436285Sbrian    if (arg->argc > arg->argn) {
141536285Sbrian      l->lcp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn]) * SECTICKS;
141636285Sbrian      if (arg->argc > arg->argn+1)
141736285Sbrian        l->ccp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn+1]) * SECTICKS;
141828461Sbrian    }
141928327Sbrian    return 0;
142028327Sbrian  }
142128327Sbrian  return -1;
142228327Sbrian}
142328327Sbrian
142428327Sbrianstatic int
142531343SbrianSetServer(struct cmdargs const *arg)
142626940Sbrian{
142726940Sbrian  int res = -1;
142826940Sbrian
142936285Sbrian  if (arg->argc > arg->argn && arg->argc < arg->argn+4) {
143031081Sbrian    const char *port, *passwd, *mask;
143153125Sbrian    int mlen;
143231081Sbrian
143331081Sbrian    /* What's what ? */
143436285Sbrian    port = arg->argv[arg->argn];
143536285Sbrian    if (arg->argc == arg->argn + 2) {
143636285Sbrian      passwd = arg->argv[arg->argn+1];
143736285Sbrian      mask = NULL;
143836285Sbrian    } else if (arg->argc == arg->argn + 3) {
143936285Sbrian      passwd = arg->argv[arg->argn+1];
144036285Sbrian      mask = arg->argv[arg->argn+2];
144153125Sbrian      mlen = strlen(mask);
144253125Sbrian      if (mlen == 0 || mlen > 4 || strspn(mask, "01234567") != mlen ||
144353125Sbrian          (mlen == 4 && *mask != '0')) {
144453125Sbrian        log_Printf(LogWARN, "%s %s: %s: Invalid mask\n",
144553125Sbrian                   arg->argv[arg->argn - 2], arg->argv[arg->argn - 1], mask);
144631081Sbrian        return -1;
144753125Sbrian      }
144871764Sbrian    } else if (arg->argc != arg->argn + 1)
144971764Sbrian      return -1;
145071764Sbrian    else if (strcasecmp(port, "none") == 0) {
145171657Sbrian      if (server_Clear(arg->bundle))
145271657Sbrian        log_Printf(LogPHASE, "Disabled server socket\n");
145371657Sbrian      return 0;
145471657Sbrian    } else if (strcasecmp(port, "open") == 0) {
145571657Sbrian      switch (server_Reopen(arg->bundle)) {
145671657Sbrian        case SERVER_OK:
145771657Sbrian          return 0;
145871657Sbrian        case SERVER_FAILED:
145971764Sbrian          log_Printf(LogWARN, "Failed to reopen server port\n");
146071657Sbrian          return 1;
146171657Sbrian        case SERVER_UNSET:
146271764Sbrian          log_Printf(LogWARN, "Cannot reopen unset server socket\n");
146371657Sbrian          return 1;
146471657Sbrian        default:
146571657Sbrian          break;
146671657Sbrian      }
146771657Sbrian      return -1;
146871657Sbrian    } else if (strcasecmp(port, "closed") == 0) {
146936285Sbrian      if (server_Close(arg->bundle))
147071657Sbrian        log_Printf(LogPHASE, "Closed server socket\n");
147171657Sbrian      else
147271657Sbrian        log_Printf(LogWARN, "Server socket not open\n");
147371657Sbrian
147436285Sbrian      return 0;
147531081Sbrian    } else
147636285Sbrian      return -1;
147731081Sbrian
147871657Sbrian    strncpy(server.cfg.passwd, passwd, sizeof server.cfg.passwd - 1);
147971657Sbrian    server.cfg.passwd[sizeof server.cfg.passwd - 1] = '\0';
148031081Sbrian
148136285Sbrian    if (*port == '/') {
148231081Sbrian      mode_t imask;
148336285Sbrian      char *ptr, name[LINE_LEN + 12];
148428679Sbrian
148553125Sbrian      if (mask == NULL)
148631081Sbrian        imask = (mode_t)-1;
148753125Sbrian      else for (imask = mlen = 0; mask[mlen]; mlen++)
148853125Sbrian        imask = (imask * 8) + mask[mlen] - '0';
148936285Sbrian
149036285Sbrian      ptr = strstr(port, "%d");
149136285Sbrian      if (ptr) {
149236285Sbrian        snprintf(name, sizeof name, "%.*s%d%s",
149337210Sbrian                 (int)(ptr - port), port, arg->bundle->unit, ptr + 2);
149436285Sbrian        port = name;
149536285Sbrian      }
149636285Sbrian      res = server_LocalOpen(arg->bundle, port, imask);
149727346Sbrian    } else {
149836285Sbrian      int iport, add = 0;
149928679Sbrian
150031081Sbrian      if (mask != NULL)
150131081Sbrian        return -1;
150228679Sbrian
150336285Sbrian      if (*port == '+') {
150436285Sbrian        port++;
150536285Sbrian        add = 1;
150636285Sbrian      }
150731081Sbrian      if (strspn(port, "0123456789") != strlen(port)) {
150831081Sbrian        struct servent *s;
150931081Sbrian
151031081Sbrian        if ((s = getservbyname(port, "tcp")) == NULL) {
151131081Sbrian	  iport = 0;
151236285Sbrian	  log_Printf(LogWARN, "%s: Invalid port or service\n", port);
151328679Sbrian	} else
151431081Sbrian	  iport = ntohs(s->s_port);
151527346Sbrian      } else
151631081Sbrian        iport = atoi(port);
151736285Sbrian
151836285Sbrian      if (iport) {
151936285Sbrian        if (add)
152036285Sbrian          iport += arg->bundle->unit;
152136285Sbrian        res = server_TcpOpen(arg->bundle, iport);
152236285Sbrian      } else
152336285Sbrian        res = -1;
152427346Sbrian    }
152531081Sbrian  }
152626940Sbrian
152726940Sbrian  return res;
152826940Sbrian}
152926940Sbrian
153026940Sbrianstatic int
153131343SbrianSetEscape(struct cmdargs const *arg)
15326059Samurai{
15336059Samurai  int code;
153436285Sbrian  int argc = arg->argc - arg->argn;
153536285Sbrian  char const *const *argv = arg->argv + arg->argn;
15366059Samurai
15376059Samurai  for (code = 0; code < 33; code++)
153836285Sbrian    arg->cx->physical->async.cfg.EscMap[code] = 0;
153931343Sbrian
15406059Samurai  while (argc-- > 0) {
15416059Samurai    sscanf(*argv++, "%x", &code);
15426059Samurai    code &= 0xff;
154336285Sbrian    arg->cx->physical->async.cfg.EscMap[code >> 3] |= (1 << (code & 7));
154436285Sbrian    arg->cx->physical->async.cfg.EscMap[32] = 1;
15456059Samurai  }
154626516Sbrian  return 0;
15476059Samurai}
15486059Samurai
15496059Samuraistatic int
155031343SbrianSetInterfaceAddr(struct cmdargs const *arg)
15516059Samurai{
155281634Sbrian  struct ncp *ncp = &arg->bundle->ncp;
155381634Sbrian  struct ncpaddr ncpaddr;
155432267Sbrian  const char *hisaddr;
155532267Sbrian
155640561Sbrian  if (arg->argc > arg->argn + 4)
155740561Sbrian    return -1;
155840561Sbrian
155932267Sbrian  hisaddr = NULL;
156081634Sbrian  memset(&ncp->ipcp.cfg.my_range, '\0', sizeof ncp->ipcp.cfg.my_range);
156181634Sbrian  memset(&ncp->ipcp.cfg.peer_range, '\0', sizeof ncp->ipcp.cfg.peer_range);
156281634Sbrian  ncp->ipcp.cfg.HaveTriggerAddress = 0;
156381634Sbrian  ncp->ipcp.cfg.netmask.s_addr = INADDR_ANY;
156481634Sbrian  iplist_reset(&ncp->ipcp.cfg.peer_list);
156528394Sbrian
156636285Sbrian  if (arg->argc > arg->argn) {
156781634Sbrian    if (!ncprange_aton(&ncp->ipcp.cfg.my_range, ncp, arg->argv[arg->argn]))
156828679Sbrian      return 1;
156936285Sbrian    if (arg->argc > arg->argn+1) {
157036285Sbrian      hisaddr = arg->argv[arg->argn+1];
157136285Sbrian      if (arg->argc > arg->argn+2) {
157281634Sbrian        ncp->ipcp.ifmask = ncp->ipcp.cfg.netmask =
157381634Sbrian          GetIpAddr(arg->argv[arg->argn+2]);
157436285Sbrian	if (arg->argc > arg->argn+3) {
157581634Sbrian	  ncp->ipcp.cfg.TriggerAddress = GetIpAddr(arg->argv[arg->argn+3]);
157681634Sbrian	  ncp->ipcp.cfg.HaveTriggerAddress = 1;
15779440Samurai	}
15786059Samurai      }
15796059Samurai    }
15806059Samurai  }
158128394Sbrian
158240561Sbrian  /* 0.0.0.0 means any address (0 bits) */
1583132204Sbrian  ncprange_getaddr(&ncp->ipcp.cfg.my_range, &ncpaddr);
158481634Sbrian  ncpaddr_getip4(&ncpaddr, &ncp->ipcp.my_ip);
158581634Sbrian  if (ncp->ipcp.my_ip.s_addr == INADDR_ANY)
158681634Sbrian    ncprange_setwidth(&ncp->ipcp.cfg.my_range, 0);
158781634Sbrian  bundle_AdjustFilters(arg->bundle, &ncpaddr, NULL);
158836285Sbrian
158936285Sbrian  if (hisaddr && !ipcp_UseHisaddr(arg->bundle, hisaddr,
159036928Sbrian                                  arg->bundle->phys_type.all & PHYS_AUTO))
159132267Sbrian    return 4;
159231121Sbrian
159326516Sbrian  return 0;
15946059Samurai}
15956059Samurai
159618752Sjkhstatic int
159744305SbrianSetRetry(int argc, char const *const *argv, u_int *timeout, u_int *maxreq,
159844305Sbrian          u_int *maxtrm, int def)
159944305Sbrian{
160044305Sbrian  if (argc == 0) {
160144305Sbrian    *timeout = DEF_FSMRETRY;
160244305Sbrian    *maxreq = def;
160344305Sbrian    if (maxtrm != NULL)
160444305Sbrian      *maxtrm = def;
160544305Sbrian  } else {
160644305Sbrian    long l = atol(argv[0]);
160744305Sbrian
160844305Sbrian    if (l < MIN_FSMRETRY) {
160944305Sbrian      log_Printf(LogWARN, "%ld: Invalid FSM retry period - min %d\n",
161044305Sbrian                 l, MIN_FSMRETRY);
161144305Sbrian      return 1;
161244305Sbrian    } else
161344305Sbrian      *timeout = l;
161444305Sbrian
161544305Sbrian    if (argc > 1) {
161644305Sbrian      l = atol(argv[1]);
161744305Sbrian      if (l < 1) {
161844305Sbrian        log_Printf(LogWARN, "%ld: Invalid FSM REQ tries - changed to 1\n", l);
161944305Sbrian        l = 1;
162044305Sbrian      }
162144305Sbrian      *maxreq = l;
162244305Sbrian
162344305Sbrian      if (argc > 2 && maxtrm != NULL) {
162444305Sbrian        l = atol(argv[2]);
162544305Sbrian        if (l < 1) {
162644305Sbrian          log_Printf(LogWARN, "%ld: Invalid FSM TRM tries - changed to 1\n", l);
162744305Sbrian          l = 1;
162844305Sbrian        }
162944305Sbrian        *maxtrm = l;
163044305Sbrian      }
163144305Sbrian    }
163244305Sbrian  }
163344305Sbrian
163444305Sbrian  return 0;
163544305Sbrian}
163644305Sbrian
163744305Sbrianstatic int
163831343SbrianSetVariable(struct cmdargs const *arg)
16396059Samurai{
164037210Sbrian  long long_val, param = (long)arg->cmd->args;
164179119Sbrian  int mode, dummyint, f, first, res;
164278410Sbrian  u_short *change;
164331343Sbrian  const char *argp;
164436285Sbrian  struct datalink *cx = arg->cx;	/* LOCAL_CX uses this */
164536285Sbrian  struct link *l = command_ChooseLink(arg);	/* LOCAL_CX_OPT uses this */
164681634Sbrian  struct in_addr *ipaddr;
164781634Sbrian  struct ncpaddr ncpaddr[2];
16486059Samurai
164936285Sbrian  if (arg->argc > arg->argn)
165036285Sbrian    argp = arg->argv[arg->argn];
165126551Sbrian  else
165231343Sbrian    argp = "";
165326551Sbrian
165479119Sbrian  res = 0;
165579119Sbrian
165636285Sbrian  if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
165736285Sbrian    log_Printf(LogWARN, "set %s: No context (use the `link' command)\n",
165836285Sbrian              arg->cmd->name);
165936285Sbrian    return 1;
166036285Sbrian  } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
166136285Sbrian    log_Printf(LogWARN, "set %s: Redundant context (%s) ignored\n",
166236285Sbrian              arg->cmd->name, cx->name);
166336285Sbrian    cx = NULL;
166436285Sbrian  }
166536285Sbrian
166626551Sbrian  switch (param) {
166728679Sbrian  case VAR_AUTHKEY:
166850139Sbrian    strncpy(arg->bundle->cfg.auth.key, argp,
166950139Sbrian            sizeof arg->bundle->cfg.auth.key - 1);
167050139Sbrian    arg->bundle->cfg.auth.key[sizeof arg->bundle->cfg.auth.key - 1] = '\0';
167128679Sbrian    break;
167237210Sbrian
167328679Sbrian  case VAR_AUTHNAME:
167440622Sbrian    switch (bundle_Phase(arg->bundle)) {
167558880Sbrian      default:
167658880Sbrian        log_Printf(LogWARN, "Altering authname while at phase %s\n",
167758880Sbrian                   bundle_PhaseName(arg->bundle));
167858880Sbrian        /* drop through */
167940622Sbrian      case PHASE_DEAD:
168040622Sbrian      case PHASE_ESTABLISH:
168140622Sbrian        strncpy(arg->bundle->cfg.auth.name, argp,
168240622Sbrian                sizeof arg->bundle->cfg.auth.name - 1);
168340622Sbrian        arg->bundle->cfg.auth.name[sizeof arg->bundle->cfg.auth.name-1] = '\0';
168440622Sbrian        break;
168536285Sbrian    }
168628679Sbrian    break;
168737210Sbrian
168836285Sbrian  case VAR_AUTOLOAD:
168949434Sbrian    if (arg->argc == arg->argn + 3) {
169098243Sbrian      int v1, v2, v3;
169149434Sbrian      char *end;
169249434Sbrian
169349434Sbrian      v1 = strtol(arg->argv[arg->argn], &end, 0);
169449434Sbrian      if (v1 < 0 || *end) {
169549434Sbrian        log_Printf(LogWARN, "autoload: %s: Invalid min percentage\n",
169649434Sbrian                   arg->argv[arg->argn]);
169779119Sbrian        res = 1;
169879119Sbrian        break;
169936285Sbrian      }
170049434Sbrian
170149434Sbrian      v2 = strtol(arg->argv[arg->argn + 1], &end, 0);
170249434Sbrian      if (v2 < 0 || *end) {
170349434Sbrian        log_Printf(LogWARN, "autoload: %s: Invalid max percentage\n",
170449434Sbrian                   arg->argv[arg->argn + 1]);
170579119Sbrian        res = 1;
170679119Sbrian        break;
170749434Sbrian      }
170849434Sbrian      if (v2 < v1) {
170949434Sbrian        v3 = v1;
171049434Sbrian        v1 = v2;
171149434Sbrian        v2 = v3;
171249434Sbrian      }
171349434Sbrian
171449434Sbrian      v3 = strtol(arg->argv[arg->argn + 2], &end, 0);
171549434Sbrian      if (v3 <= 0 || *end) {
171649434Sbrian        log_Printf(LogWARN, "autoload: %s: Invalid throughput period\n",
171749434Sbrian                   arg->argv[arg->argn + 2]);
171879119Sbrian        res = 1;
171979119Sbrian        break;
172049434Sbrian      }
172149434Sbrian
172249434Sbrian      arg->bundle->ncp.mp.cfg.autoload.min = v1;
172349434Sbrian      arg->bundle->ncp.mp.cfg.autoload.max = v2;
172449434Sbrian      arg->bundle->ncp.mp.cfg.autoload.period = v3;
172549434Sbrian      mp_RestartAutoloadTimer(&arg->bundle->ncp.mp);
172636285Sbrian    } else {
172779119Sbrian      log_Printf(LogWARN, "Set autoload requires three arguments\n");
172879119Sbrian      res = 1;
172936285Sbrian    }
173036285Sbrian    break;
173137210Sbrian
173228679Sbrian  case VAR_DIAL:
173336285Sbrian    strncpy(cx->cfg.script.dial, argp, sizeof cx->cfg.script.dial - 1);
173436285Sbrian    cx->cfg.script.dial[sizeof cx->cfg.script.dial - 1] = '\0';
173528679Sbrian    break;
173637210Sbrian
173728679Sbrian  case VAR_LOGIN:
173836285Sbrian    strncpy(cx->cfg.script.login, argp, sizeof cx->cfg.script.login - 1);
173936285Sbrian    cx->cfg.script.login[sizeof cx->cfg.script.login - 1] = '\0';
174028679Sbrian    break;
174137210Sbrian
174236285Sbrian  case VAR_WINSIZE:
174336285Sbrian    if (arg->argc > arg->argn) {
174436285Sbrian      l->ccp.cfg.deflate.out.winsize = atoi(arg->argv[arg->argn]);
174536285Sbrian      if (l->ccp.cfg.deflate.out.winsize < 8 ||
174636285Sbrian          l->ccp.cfg.deflate.out.winsize > 15) {
174736285Sbrian          log_Printf(LogWARN, "%d: Invalid outgoing window size\n",
174836285Sbrian                    l->ccp.cfg.deflate.out.winsize);
174936285Sbrian          l->ccp.cfg.deflate.out.winsize = 15;
175036285Sbrian      }
175136285Sbrian      if (arg->argc > arg->argn+1) {
175236285Sbrian        l->ccp.cfg.deflate.in.winsize = atoi(arg->argv[arg->argn+1]);
175336285Sbrian        if (l->ccp.cfg.deflate.in.winsize < 8 ||
175436285Sbrian            l->ccp.cfg.deflate.in.winsize > 15) {
175536285Sbrian            log_Printf(LogWARN, "%d: Invalid incoming window size\n",
175636285Sbrian                      l->ccp.cfg.deflate.in.winsize);
175736285Sbrian            l->ccp.cfg.deflate.in.winsize = 15;
175836285Sbrian        }
175936285Sbrian      } else
176036285Sbrian        l->ccp.cfg.deflate.in.winsize = 0;
176136285Sbrian    } else {
176279119Sbrian      log_Printf(LogWARN, "No window size specified\n");
176379119Sbrian      res = 1;
176436285Sbrian    }
176536285Sbrian    break;
176637210Sbrian
176793418Sbrian#ifndef NODES
176878411Sbrian  case VAR_MPPE:
176979119Sbrian    if (arg->argc > arg->argn + 2) {
177079119Sbrian      res = -1;
177179119Sbrian      break;
177279119Sbrian    }
177378411Sbrian
177478411Sbrian    if (arg->argc == arg->argn) {
177578411Sbrian      l->ccp.cfg.mppe.keybits = 0;
177678411Sbrian      l->ccp.cfg.mppe.state = MPPE_ANYSTATE;
177778411Sbrian      l->ccp.cfg.mppe.required = 0;
177878411Sbrian      break;
177978411Sbrian    }
178078411Sbrian
178178411Sbrian    if (!strcmp(argp, "*"))
178278411Sbrian      long_val = 0;
178378411Sbrian    else {
178478411Sbrian      long_val = atol(argp);
178578411Sbrian      if (long_val != 40 && long_val != 56 && long_val != 128) {
178678411Sbrian        log_Printf(LogWARN, "%s: Invalid bits value\n", argp);
178779119Sbrian        res = -1;
178879119Sbrian        break;
178967910Sbrian      }
179067910Sbrian    }
179178411Sbrian
179278411Sbrian    if (arg->argc == arg->argn + 2) {
179378411Sbrian      if (!strcmp(arg->argv[arg->argn + 1], "*"))
179478411Sbrian        l->ccp.cfg.mppe.state = MPPE_ANYSTATE;
179578411Sbrian      else if (!strcasecmp(arg->argv[arg->argn + 1], "stateless"))
179678411Sbrian        l->ccp.cfg.mppe.state = MPPE_STATELESS;
179779370Sbrian      else if (!strcasecmp(arg->argv[arg->argn + 1], "stateful"))
179878411Sbrian        l->ccp.cfg.mppe.state = MPPE_STATEFUL;
179978411Sbrian      else {
180078411Sbrian        log_Printf(LogWARN, "%s: Invalid state value\n",
180178411Sbrian                   arg->argv[arg->argn + 1]);
180279119Sbrian        res = -1;
180379119Sbrian        break;
180478411Sbrian      }
180578411Sbrian    } else
180678411Sbrian      l->ccp.cfg.mppe.state = MPPE_ANYSTATE;
180778411Sbrian    l->ccp.cfg.mppe.keybits = long_val;
180878411Sbrian    l->ccp.cfg.mppe.required = 1;
180967910Sbrian    break;
181067910Sbrian#endif
181167910Sbrian
181228679Sbrian  case VAR_DEVICE:
181336285Sbrian    physical_SetDeviceList(cx->physical, arg->argc - arg->argn,
181436285Sbrian                           arg->argv + arg->argn);
181536285Sbrian    break;
181637210Sbrian
181736285Sbrian  case VAR_ACCMAP:
181836285Sbrian    if (arg->argc > arg->argn) {
181937210Sbrian      u_long ulong_val;
182036285Sbrian      sscanf(argp, "%lx", &ulong_val);
182137210Sbrian      cx->physical->link.lcp.cfg.accmap = (u_int32_t)ulong_val;
182236285Sbrian    } else {
182379119Sbrian      log_Printf(LogWARN, "No accmap specified\n");
182479119Sbrian      res = 1;
182536285Sbrian    }
182636285Sbrian    break;
182737210Sbrian
182836285Sbrian  case VAR_MODE:
182936285Sbrian    mode = Nam2mode(argp);
183036285Sbrian    if (mode == PHYS_NONE || mode == PHYS_ALL) {
183136285Sbrian      log_Printf(LogWARN, "%s: Invalid mode\n", argp);
183279119Sbrian      res = -1;
183379119Sbrian      break;
183436285Sbrian    }
183536285Sbrian    bundle_SetMode(arg->bundle, cx, mode);
183636285Sbrian    break;
183737210Sbrian
183836285Sbrian  case VAR_MRRU:
183940622Sbrian    switch (bundle_Phase(arg->bundle)) {
184040622Sbrian      case PHASE_DEAD:
184140622Sbrian        break;
184240622Sbrian      case PHASE_ESTABLISH:
184340622Sbrian        /* Make sure none of our links are DATALINK_LCP or greater */
184440622Sbrian        if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) {
184540622Sbrian          log_Printf(LogWARN, "mrru: Only changable before LCP negotiations\n");
184679119Sbrian          res = 1;
184779119Sbrian          break;
184840622Sbrian        }
184940622Sbrian        break;
185040622Sbrian      default:
185140622Sbrian        log_Printf(LogWARN, "mrru: Only changable at phase DEAD/ESTABLISH\n");
185279119Sbrian        res = 1;
185379119Sbrian        break;
185429696Sbrian    }
185579119Sbrian    if (res != 0)
185679119Sbrian      break;
185737210Sbrian    long_val = atol(argp);
185837210Sbrian    if (long_val && long_val < MIN_MRU) {
185937210Sbrian      log_Printf(LogWARN, "MRRU %ld: too small - min %d\n", long_val, MIN_MRU);
186079119Sbrian      res = 1;
186179119Sbrian      break;
186237210Sbrian    } else if (long_val > MAX_MRU) {
186337210Sbrian      log_Printf(LogWARN, "MRRU %ld: too big - max %d\n", long_val, MAX_MRU);
186479119Sbrian      res = 1;
186579119Sbrian      break;
186637210Sbrian    } else
186737210Sbrian      arg->bundle->ncp.mp.cfg.mrru = long_val;
186828679Sbrian    break;
186937210Sbrian
187036285Sbrian  case VAR_MRU:
187179163Sbrian    long_val = 0;	/* silence gcc */
187279163Sbrian    change = NULL;	/* silence gcc */
187378410Sbrian    switch(arg->argc - arg->argn) {
187478410Sbrian    case 1:
187579119Sbrian      if (argp[strspn(argp, "0123456789")] != '\0') {
187679119Sbrian        res = -1;
187779119Sbrian        break;
187879119Sbrian      }
187979119Sbrian      /*FALLTHRU*/
188078410Sbrian    case 0:
188178410Sbrian      long_val = atol(argp);
188278410Sbrian      change = &l->lcp.cfg.mru;
188378410Sbrian      if (long_val > l->lcp.cfg.max_mru) {
188478410Sbrian        log_Printf(LogWARN, "MRU %ld: too large - max set to %d\n", long_val,
188578410Sbrian                   l->lcp.cfg.max_mru);
188679119Sbrian        res = 1;
188779119Sbrian        break;
188878410Sbrian      }
188978410Sbrian      break;
189078410Sbrian    case 2:
189179119Sbrian      if (strcasecmp(argp, "max") && strcasecmp(argp, "maximum")) {
189279119Sbrian        res = -1;
189379119Sbrian        break;
189479119Sbrian      }
189578410Sbrian      long_val = atol(arg->argv[arg->argn + 1]);
189678410Sbrian      change = &l->lcp.cfg.max_mru;
189778410Sbrian      if (long_val > MAX_MRU) {
189878410Sbrian        log_Printf(LogWARN, "MRU %ld: too large - maximum is %d\n", long_val,
189978410Sbrian                   MAX_MRU);
190079119Sbrian        res = 1;
190179119Sbrian        break;
190278410Sbrian      }
190378410Sbrian      break;
190478410Sbrian    default:
190579119Sbrian      res = -1;
190679119Sbrian      break;
190778410Sbrian    }
190879119Sbrian    if (res != 0)
190979119Sbrian      break;
191078410Sbrian
191137210Sbrian    if (long_val == 0)
191280385Sbrian      *change = 0;
191337210Sbrian    else if (long_val < MIN_MRU) {
191437210Sbrian      log_Printf(LogWARN, "MRU %ld: too small - min %d\n", long_val, MIN_MRU);
191579119Sbrian      res = 1;
191679119Sbrian      break;
191737210Sbrian    } else if (long_val > MAX_MRU) {
191837210Sbrian      log_Printf(LogWARN, "MRU %ld: too big - max %d\n", long_val, MAX_MRU);
191979119Sbrian      res = 1;
192079119Sbrian      break;
192137210Sbrian    } else
192278410Sbrian      *change = long_val;
192378410Sbrian    if (l->lcp.cfg.mru > *change)
192478410Sbrian      l->lcp.cfg.mru = *change;
192528679Sbrian    break;
192637210Sbrian
192736285Sbrian  case VAR_MTU:
192879163Sbrian    long_val = 0;	/* silence gcc */
192979163Sbrian    change = NULL;	/* silence gcc */
193078410Sbrian    switch(arg->argc - arg->argn) {
193178410Sbrian    case 1:
193279119Sbrian      if (argp[strspn(argp, "0123456789")] != '\0') {
193379119Sbrian        res = -1;
193479119Sbrian        break;
193579119Sbrian      }
193679119Sbrian      /*FALLTHRU*/
193778410Sbrian    case 0:
193878410Sbrian      long_val = atol(argp);
193978410Sbrian      change = &l->lcp.cfg.mtu;
194078410Sbrian      if (long_val > l->lcp.cfg.max_mtu) {
194178410Sbrian        log_Printf(LogWARN, "MTU %ld: too large - max set to %d\n", long_val,
194278410Sbrian                   l->lcp.cfg.max_mtu);
194379119Sbrian        res = 1;
194479119Sbrian        break;
194578410Sbrian      }
194678410Sbrian      break;
194778410Sbrian    case 2:
194879119Sbrian      if (strcasecmp(argp, "max") && strcasecmp(argp, "maximum")) {
194979119Sbrian        res = -1;
195079119Sbrian        break;
195179119Sbrian      }
195278410Sbrian      long_val = atol(arg->argv[arg->argn + 1]);
195378410Sbrian      change = &l->lcp.cfg.max_mtu;
195478410Sbrian      if (long_val > MAX_MTU) {
195578410Sbrian        log_Printf(LogWARN, "MTU %ld: too large - maximum is %d\n", long_val,
195678410Sbrian                   MAX_MTU);
195779119Sbrian        res = 1;
195879119Sbrian        break;
195978410Sbrian      }
196078410Sbrian      break;
196178410Sbrian    default:
196279119Sbrian      res = -1;
196379119Sbrian      break;
196478410Sbrian    }
196578410Sbrian
196679119Sbrian    if (res != 0)
196779119Sbrian      break;
196879119Sbrian
196937210Sbrian    if (long_val && long_val < MIN_MTU) {
197037210Sbrian      log_Printf(LogWARN, "MTU %ld: too small - min %d\n", long_val, MIN_MTU);
197179119Sbrian      res = 1;
197279119Sbrian      break;
197337210Sbrian    } else if (long_val > MAX_MTU) {
197437210Sbrian      log_Printf(LogWARN, "MTU %ld: too big - max %d\n", long_val, MAX_MTU);
197579119Sbrian      res = 1;
197679119Sbrian      break;
197737210Sbrian    } else
197878410Sbrian      *change = long_val;
197978410Sbrian    if (l->lcp.cfg.mtu > *change)
198078410Sbrian      l->lcp.cfg.mtu = *change;
198136285Sbrian    break;
198237210Sbrian
198336285Sbrian  case VAR_OPENMODE:
198436285Sbrian    if (strcasecmp(argp, "active") == 0)
198536285Sbrian      cx->physical->link.lcp.cfg.openmode = arg->argc > arg->argn+1 ?
198636285Sbrian        atoi(arg->argv[arg->argn+1]) : 1;
198736285Sbrian    else if (strcasecmp(argp, "passive") == 0)
198836285Sbrian      cx->physical->link.lcp.cfg.openmode = OPEN_PASSIVE;
198936285Sbrian    else {
199079119Sbrian      log_Printf(LogWARN, "%s: Invalid openmode\n", argp);
199179119Sbrian      res = 1;
199236285Sbrian    }
199336285Sbrian    break;
199437210Sbrian
199528679Sbrian  case VAR_PHONE:
199636285Sbrian    strncpy(cx->cfg.phone.list, argp, sizeof cx->cfg.phone.list - 1);
199736285Sbrian    cx->cfg.phone.list[sizeof cx->cfg.phone.list - 1] = '\0';
199838174Sbrian    cx->phone.alt = cx->phone.next = NULL;
199928679Sbrian    break;
200037210Sbrian
200128679Sbrian  case VAR_HANGUP:
200236285Sbrian    strncpy(cx->cfg.script.hangup, argp, sizeof cx->cfg.script.hangup - 1);
200336285Sbrian    cx->cfg.script.hangup[sizeof cx->cfg.script.hangup - 1] = '\0';
200428679Sbrian    break;
200537210Sbrian
200661534Sbrian  case VAR_IFQUEUE:
200761534Sbrian    long_val = atol(argp);
200861534Sbrian    arg->bundle->cfg.ifqueue = long_val < 0 ? 0 : long_val;
200961534Sbrian    break;
201061534Sbrian
201152488Sbrian  case VAR_LOGOUT:
201252488Sbrian    strncpy(cx->cfg.script.logout, argp, sizeof cx->cfg.script.logout - 1);
201352488Sbrian    cx->cfg.script.logout[sizeof cx->cfg.script.logout - 1] = '\0';
201452488Sbrian    break;
201552488Sbrian
201636285Sbrian  case VAR_IDLETIMEOUT:
201779119Sbrian    if (arg->argc > arg->argn+2) {
201879119Sbrian      log_Printf(LogWARN, "Too many idle timeout values\n");
201979119Sbrian      res = 1;
202079119Sbrian    } else if (arg->argc == arg->argn) {
202179119Sbrian      log_Printf(LogWARN, "Too few idle timeout values\n");
202279119Sbrian      res = 1;
202379119Sbrian    } else {
202449978Sbrian      int timeout, min;
202549978Sbrian
202649978Sbrian      timeout = atoi(argp);
202749978Sbrian      min = arg->argc == arg->argn + 2 ? atoi(arg->argv[arg->argn + 1]) : -1;
202849978Sbrian      bundle_SetIdleTimer(arg->bundle, timeout, min);
202949978Sbrian    }
203029549Sbrian    break;
2031132273Sbrian
2032132273Sbrian#ifndef NORADIUS
2033132273Sbrian  case VAR_RAD_ALIVE:
2034132273Sbrian    if (arg->argc > arg->argn + 2) {
2035132273Sbrian      log_Printf(LogWARN, "Too many RADIUS alive interval values\n");
2036132273Sbrian      res = 1;
2037132273Sbrian    } else if (arg->argc == arg->argn) {
2038132273Sbrian      log_Printf(LogWARN, "Too few RADIUS alive interval values\n");
2039132273Sbrian      res = 1;
2040132273Sbrian    } else {
2041132273Sbrian      arg->bundle->radius.alive.interval = atoi(argp);
2042132273Sbrian      if (arg->bundle->radius.alive.interval && !arg->bundle->radius.cfg.file) {
2043132273Sbrian        log_Printf(LogWARN, "rad_alive requires radius to be configured\n");
2044132273Sbrian	res = 1;
2045132273Sbrian      } else if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED) {
2046132273Sbrian	if (arg->bundle->radius.alive.interval)
2047132273Sbrian	  radius_StartTimer(arg->bundle);
2048132273Sbrian	else
2049132273Sbrian	  radius_StopTimer(&arg->bundle->radius);
2050132273Sbrian      }
2051132273Sbrian    }
2052132273Sbrian    break;
2053132273Sbrian#endif
2054132273Sbrian
205536285Sbrian  case VAR_LQRPERIOD:
205637210Sbrian    long_val = atol(argp);
205737210Sbrian    if (long_val < MIN_LQRPERIOD) {
205837210Sbrian      log_Printf(LogWARN, "%ld: Invalid lqr period - min %d\n",
205937210Sbrian                 long_val, MIN_LQRPERIOD);
206079119Sbrian      res = 1;
206136285Sbrian    } else
206237210Sbrian      l->lcp.cfg.lqrperiod = long_val;
206336285Sbrian    break;
206437210Sbrian
206536285Sbrian  case VAR_LCPRETRY:
206679119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
206779119Sbrian                   &cx->physical->link.lcp.cfg.fsm.timeout,
206879119Sbrian                   &cx->physical->link.lcp.cfg.fsm.maxreq,
206979119Sbrian                   &cx->physical->link.lcp.cfg.fsm.maxtrm, DEF_FSMTRIES);
207036285Sbrian    break;
207137210Sbrian
207236285Sbrian  case VAR_CHAPRETRY:
207379119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
207479119Sbrian                   &cx->chap.auth.cfg.fsm.timeout,
207579119Sbrian                   &cx->chap.auth.cfg.fsm.maxreq, NULL, DEF_FSMAUTHTRIES);
207636285Sbrian    break;
207737210Sbrian
207836285Sbrian  case VAR_PAPRETRY:
207979119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
208079119Sbrian                   &cx->pap.cfg.fsm.timeout, &cx->pap.cfg.fsm.maxreq,
208179119Sbrian                   NULL, DEF_FSMAUTHTRIES);
208236285Sbrian    break;
208337210Sbrian
208436285Sbrian  case VAR_CCPRETRY:
208579119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
208679119Sbrian                   &l->ccp.cfg.fsm.timeout, &l->ccp.cfg.fsm.maxreq,
208779119Sbrian                   &l->ccp.cfg.fsm.maxtrm, DEF_FSMTRIES);
208836285Sbrian    break;
208937210Sbrian
209036285Sbrian  case VAR_IPCPRETRY:
209179119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
209279119Sbrian                   &arg->bundle->ncp.ipcp.cfg.fsm.timeout,
209379119Sbrian                   &arg->bundle->ncp.ipcp.cfg.fsm.maxreq,
209479119Sbrian                   &arg->bundle->ncp.ipcp.cfg.fsm.maxtrm, DEF_FSMTRIES);
209536285Sbrian    break;
209637210Sbrian
2097102855Sbrian#ifndef NOINET6
2098102558Sbrian  case VAR_IPV6CPRETRY:
2099102558Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
2100102558Sbrian                   &arg->bundle->ncp.ipv6cp.cfg.fsm.timeout,
2101102558Sbrian                   &arg->bundle->ncp.ipv6cp.cfg.fsm.maxreq,
2102102558Sbrian                   &arg->bundle->ncp.ipv6cp.cfg.fsm.maxtrm, DEF_FSMTRIES);
2103102558Sbrian    break;
2104102855Sbrian#endif
2105102558Sbrian
210636285Sbrian  case VAR_NBNS:
210736285Sbrian  case VAR_DNS:
210858044Sbrian    if (param == VAR_DNS) {
210981634Sbrian      ipaddr = arg->bundle->ncp.ipcp.cfg.ns.dns;
211081634Sbrian      ipaddr[0].s_addr = ipaddr[1].s_addr = INADDR_NONE;
211158044Sbrian    } else {
211281634Sbrian      ipaddr = arg->bundle->ncp.ipcp.cfg.ns.nbns;
211381634Sbrian      ipaddr[0].s_addr = ipaddr[1].s_addr = INADDR_ANY;
211458044Sbrian    }
211536285Sbrian
211636285Sbrian    if (arg->argc > arg->argn) {
211781634Sbrian      ncpaddr_aton(ncpaddr, &arg->bundle->ncp, arg->argv[arg->argn]);
211881634Sbrian      if (!ncpaddr_getip4(ncpaddr, ipaddr))
211981634Sbrian        return -1;
212081634Sbrian      if (arg->argc > arg->argn+1) {
212181634Sbrian        ncpaddr_aton(ncpaddr + 1, &arg->bundle->ncp, arg->argv[arg->argn + 1]);
212281634Sbrian        if (!ncpaddr_getip4(ncpaddr + 1, ipaddr + 1))
212381634Sbrian          return -1;
212481634Sbrian      }
212536285Sbrian
212681634Sbrian      if (ipaddr[0].s_addr == INADDR_ANY) {
212781634Sbrian        ipaddr[0] = ipaddr[1];
212881634Sbrian        ipaddr[1].s_addr = INADDR_ANY;
212958044Sbrian      }
213081634Sbrian      if (ipaddr[0].s_addr == INADDR_NONE) {
213181634Sbrian        ipaddr[0] = ipaddr[1];
213281634Sbrian        ipaddr[1].s_addr = INADDR_NONE;
213358044Sbrian      }
213436285Sbrian    }
213536285Sbrian    break;
213638174Sbrian
213738174Sbrian  case VAR_CALLBACK:
213838174Sbrian    cx->cfg.callback.opmask = 0;
213938174Sbrian    for (dummyint = arg->argn; dummyint < arg->argc; dummyint++) {
214038174Sbrian      if (!strcasecmp(arg->argv[dummyint], "auth"))
214138174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_AUTH);
214238174Sbrian      else if (!strcasecmp(arg->argv[dummyint], "cbcp"))
214338174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_CBCP);
214438174Sbrian      else if (!strcasecmp(arg->argv[dummyint], "e.164")) {
214538174Sbrian        if (dummyint == arg->argc - 1)
214638174Sbrian          log_Printf(LogWARN, "No E.164 arg (E.164 ignored) !\n");
214738174Sbrian        else {
214838174Sbrian          cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_E164);
214938174Sbrian          strncpy(cx->cfg.callback.msg, arg->argv[++dummyint],
215038174Sbrian                  sizeof cx->cfg.callback.msg - 1);
215138174Sbrian          cx->cfg.callback.msg[sizeof cx->cfg.callback.msg - 1] = '\0';
215238174Sbrian        }
215338174Sbrian      } else if (!strcasecmp(arg->argv[dummyint], "none"))
215438174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_NONE);
215579119Sbrian      else {
215679119Sbrian        res = -1;
215779119Sbrian        break;
215879119Sbrian      }
215938174Sbrian    }
216038174Sbrian    if (cx->cfg.callback.opmask == CALLBACK_BIT(CALLBACK_NONE))
216138174Sbrian      cx->cfg.callback.opmask = 0;
216238174Sbrian    break;
216338174Sbrian
216438174Sbrian  case VAR_CBCP:
216538174Sbrian    cx->cfg.cbcp.delay = 0;
216638174Sbrian    *cx->cfg.cbcp.phone = '\0';
216738174Sbrian    cx->cfg.cbcp.fsmretry = DEF_FSMRETRY;
216838174Sbrian    if (arg->argc > arg->argn) {
216938174Sbrian      strncpy(cx->cfg.cbcp.phone, arg->argv[arg->argn],
217038174Sbrian              sizeof cx->cfg.cbcp.phone - 1);
217138174Sbrian      cx->cfg.cbcp.phone[sizeof cx->cfg.cbcp.phone - 1] = '\0';
217238174Sbrian      if (arg->argc > arg->argn + 1) {
217338174Sbrian        cx->cfg.cbcp.delay = atoi(arg->argv[arg->argn + 1]);
217438174Sbrian        if (arg->argc > arg->argn + 2) {
217538174Sbrian          long_val = atol(arg->argv[arg->argn + 2]);
217638174Sbrian          if (long_val < MIN_FSMRETRY)
217738174Sbrian            log_Printf(LogWARN, "%ld: Invalid CBCP FSM retry period - min %d\n",
217838174Sbrian                       long_val, MIN_FSMRETRY);
217938174Sbrian          else
218038174Sbrian            cx->cfg.cbcp.fsmretry = long_val;
218138174Sbrian        }
218238174Sbrian      }
218338174Sbrian    }
218438174Sbrian    break;
218538544Sbrian
218638544Sbrian  case VAR_CHOKED:
218738544Sbrian    arg->bundle->cfg.choked.timeout = atoi(argp);
218838544Sbrian    if (arg->bundle->cfg.choked.timeout <= 0)
218938544Sbrian      arg->bundle->cfg.choked.timeout = CHOKED_TIMEOUT;
219038544Sbrian    break;
219140665Sbrian
219240665Sbrian  case VAR_SENDPIPE:
219340665Sbrian    long_val = atol(argp);
219481634Sbrian    arg->bundle->ncp.cfg.sendpipe = long_val;
219540665Sbrian    break;
219640665Sbrian
219740665Sbrian  case VAR_RECVPIPE:
219840665Sbrian    long_val = atol(argp);
219981634Sbrian    arg->bundle->ncp.cfg.recvpipe = long_val;
220040665Sbrian    break;
220143313Sbrian
220243313Sbrian#ifndef NORADIUS
220343313Sbrian  case VAR_RADIUS:
220443313Sbrian    if (!*argp)
220543313Sbrian      *arg->bundle->radius.cfg.file = '\0';
220643313Sbrian    else if (access(argp, R_OK)) {
220743313Sbrian      log_Printf(LogWARN, "%s: %s\n", argp, strerror(errno));
220879119Sbrian      res = 1;
220979119Sbrian      break;
221043313Sbrian    } else {
221143313Sbrian      strncpy(arg->bundle->radius.cfg.file, argp,
221243313Sbrian              sizeof arg->bundle->radius.cfg.file - 1);
221343313Sbrian      arg->bundle->radius.cfg.file
221443313Sbrian        [sizeof arg->bundle->radius.cfg.file - 1] = '\0';
221543313Sbrian    }
221643313Sbrian    break;
221743313Sbrian#endif
221844073Sbrian
221944073Sbrian  case VAR_CD:
222044073Sbrian    if (*argp) {
222151699Sbrian      if (strcasecmp(argp, "off")) {
222251699Sbrian        long_val = atol(argp);
222351699Sbrian        if (long_val < 0)
222451699Sbrian          long_val = 0;
222551699Sbrian        cx->physical->cfg.cd.delay = long_val;
222651699Sbrian        cx->physical->cfg.cd.necessity = argp[strlen(argp)-1] == '!' ?
222751699Sbrian          CD_REQUIRED : CD_VARIABLE;
222851699Sbrian      } else
222951699Sbrian        cx->physical->cfg.cd.necessity = CD_NOTREQUIRED;
223044073Sbrian    } else {
223153733Sbrian      cx->physical->cfg.cd.delay = 0;
223253733Sbrian      cx->physical->cfg.cd.necessity = CD_DEFAULT;
223344073Sbrian    }
223444073Sbrian    break;
223536285Sbrian
223646686Sbrian  case VAR_PARITY:
223746686Sbrian    if (arg->argc == arg->argn + 1)
223879119Sbrian      res = physical_SetParity(arg->cx->physical, argp);
223946686Sbrian    else {
224079119Sbrian      log_Printf(LogWARN, "Parity value must be odd, even or none\n");
224179119Sbrian      res = 1;
224246686Sbrian    }
224346686Sbrian    break;
22446059Samurai
224546686Sbrian  case VAR_CRTSCTS:
224646686Sbrian    if (strcasecmp(argp, "on") == 0)
224736285Sbrian      physical_SetRtsCts(arg->cx->physical, 1);
224846686Sbrian    else if (strcasecmp(argp, "off") == 0)
224936285Sbrian      physical_SetRtsCts(arg->cx->physical, 0);
225046686Sbrian    else {
225179119Sbrian      log_Printf(LogWARN, "RTS/CTS value must be on or off\n");
225279119Sbrian      res = 1;
225346686Sbrian    }
225446686Sbrian    break;
225550867Sbrian
225650867Sbrian  case VAR_URGENTPORTS:
225751048Sbrian    if (arg->argn == arg->argc) {
225881634Sbrian      ncp_SetUrgentTOS(&arg->bundle->ncp);
225981634Sbrian      ncp_ClearUrgentTcpPorts(&arg->bundle->ncp);
226081634Sbrian      ncp_ClearUrgentUdpPorts(&arg->bundle->ncp);
226151048Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "udp")) {
226281634Sbrian      ncp_SetUrgentTOS(&arg->bundle->ncp);
226351048Sbrian      if (arg->argn == arg->argc - 1)
226481634Sbrian        ncp_ClearUrgentUdpPorts(&arg->bundle->ncp);
226551048Sbrian      else for (f = arg->argn + 1; f < arg->argc; f++)
226651048Sbrian        if (*arg->argv[f] == '+')
226781634Sbrian          ncp_AddUrgentUdpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1));
226851048Sbrian        else if (*arg->argv[f] == '-')
226981634Sbrian          ncp_RemoveUrgentUdpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1));
227051048Sbrian        else {
227151048Sbrian          if (f == arg->argn)
227281634Sbrian            ncp_ClearUrgentUdpPorts(&arg->bundle->ncp);
227381634Sbrian          ncp_AddUrgentUdpPort(&arg->bundle->ncp, atoi(arg->argv[f]));
227451048Sbrian        }
227561430Sbrian    } else if (arg->argn == arg->argc - 1 &&
227661430Sbrian               !strcasecmp(arg->argv[arg->argn], "none")) {
227781634Sbrian      ncp_ClearUrgentTcpPorts(&arg->bundle->ncp);
227881634Sbrian      ncp_ClearUrgentUdpPorts(&arg->bundle->ncp);
227981634Sbrian      ncp_ClearUrgentTOS(&arg->bundle->ncp);
228051048Sbrian    } else {
228181634Sbrian      ncp_SetUrgentTOS(&arg->bundle->ncp);
228251048Sbrian      first = arg->argn;
228351048Sbrian      if (!strcasecmp(arg->argv[first], "tcp") && ++first == arg->argc)
228481634Sbrian        ncp_ClearUrgentTcpPorts(&arg->bundle->ncp);
228551048Sbrian
228651048Sbrian      for (f = first; f < arg->argc; f++)
228751048Sbrian        if (*arg->argv[f] == '+')
228881634Sbrian          ncp_AddUrgentTcpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1));
228951048Sbrian        else if (*arg->argv[f] == '-')
229081634Sbrian          ncp_RemoveUrgentTcpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1));
229151048Sbrian        else {
229251048Sbrian          if (f == first)
229381634Sbrian            ncp_ClearUrgentTcpPorts(&arg->bundle->ncp);
229481634Sbrian          ncp_AddUrgentTcpPort(&arg->bundle->ncp, atoi(arg->argv[f]));
229551048Sbrian        }
229651048Sbrian    }
229750867Sbrian    break;
2298132818Sglebius
2299132818Sglebius  case VAR_PPPOE:
2300132818Sglebius    if (strcasecmp(argp, "3Com") == 0)
2301132818Sglebius      physical_SetPPPoEnonstandard(arg->cx->physical, 1);
2302132818Sglebius    else if (strcasecmp(argp, "standard") == 0)
2303132818Sglebius      physical_SetPPPoEnonstandard(arg->cx->physical, 0);
2304132818Sglebius    else {
2305132818Sglebius      log_Printf(LogWARN, "PPPoE standard value must be \"standard\" or \"3Com\"\n");
2306132818Sglebius      res = 1;
2307132818Sglebius    }
2308132818Sglebius    break;
2309132818Sglebius
231020812Sjkh  }
231146686Sbrian
231279119Sbrian  return res;
231320812Sjkh}
231420812Sjkh
231530715Sbrianstatic struct cmdtab const SetCommands[] = {
231636285Sbrian  {"accmap", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
231736285Sbrian  "accmap value", "set accmap hex-value", (const void *)VAR_ACCMAP},
231828679Sbrian  {"authkey", "key", SetVariable, LOCAL_AUTH,
231936285Sbrian  "authentication key", "set authkey|key key", (const void *)VAR_AUTHKEY},
232028679Sbrian  {"authname", NULL, SetVariable, LOCAL_AUTH,
232136285Sbrian  "authentication name", "set authname name", (const void *)VAR_AUTHNAME},
232236285Sbrian  {"autoload", NULL, SetVariable, LOCAL_AUTH,
232336285Sbrian  "auto link [de]activation", "set autoload maxtime maxload mintime minload",
232436285Sbrian  (const void *)VAR_AUTOLOAD},
232550867Sbrian  {"bandwidth", NULL, mp_SetDatalinkBandwidth, LOCAL_AUTH | LOCAL_CX,
232650867Sbrian  "datalink bandwidth", "set bandwidth value"},
232738174Sbrian  {"callback", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
232838174Sbrian  "callback control", "set callback [none|auth|cbcp|"
232938174Sbrian  "E.164 *|number[,number]...]...", (const void *)VAR_CALLBACK},
233038174Sbrian  {"cbcp", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
233198243Sbrian  "CBCP control", "set cbcp [*|phone[,phone...] [delay [timeout]]]",
233238174Sbrian  (const void *)VAR_CBCP},
233344305Sbrian  {"ccpretry", "ccpretries", SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
233444305Sbrian   "CCP retries", "set ccpretry value [attempts]", (const void *)VAR_CCPRETRY},
233544073Sbrian  {"cd", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "Carrier delay requirement",
233644073Sbrian   "set cd value[!]", (const void *)VAR_CD},
233744305Sbrian  {"chapretry", "chapretries", SetVariable, LOCAL_AUTH | LOCAL_CX,
233844305Sbrian   "CHAP retries", "set chapretry value [attempts]",
233944305Sbrian   (const void *)VAR_CHAPRETRY},
234038544Sbrian  {"choked", NULL, SetVariable, LOCAL_AUTH,
234138544Sbrian  "choked timeout", "set choked [secs]", (const void *)VAR_CHOKED},
234246686Sbrian  {"ctsrts", "crtscts", SetVariable, LOCAL_AUTH | LOCAL_CX,
234346686Sbrian   "Use hardware flow control", "set ctsrts [on|off]",
234446686Sbrian   (const char *)VAR_CRTSCTS},
234536285Sbrian  {"deflate", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
234636285Sbrian  "deflate window sizes", "set deflate out-winsize in-winsize",
234736285Sbrian  (const void *) VAR_WINSIZE},
234893418Sbrian#ifndef NODES
234967910Sbrian  {"mppe", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
235098243Sbrian  "MPPE key size and state", "set mppe [40|56|128|* [stateful|stateless|*]]",
235178411Sbrian  (const void *) VAR_MPPE},
235267910Sbrian#endif
235336285Sbrian  {"device", "line", SetVariable, LOCAL_AUTH | LOCAL_CX,
235446686Sbrian  "physical device name", "set device|line device-name[,device-name]",
235536285Sbrian  (const void *) VAR_DEVICE},
235636285Sbrian  {"dial", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
235736285Sbrian  "dialing script", "set dial chat-script", (const void *) VAR_DIAL},
235836285Sbrian  {"dns", NULL, SetVariable, LOCAL_AUTH, "Domain Name Server",
235936285Sbrian  "set dns pri-addr [sec-addr]", (const void *)VAR_DNS},
236036285Sbrian  {"enddisc", NULL, mp_SetEnddisc, LOCAL_AUTH,
236136285Sbrian  "Endpoint Discriminator", "set enddisc [IP|magic|label|psn value]"},
236236285Sbrian  {"escape", NULL, SetEscape, LOCAL_AUTH | LOCAL_CX,
236336285Sbrian  "escape characters", "set escape hex-digit ..."},
236436285Sbrian  {"filter", NULL, filter_Set, LOCAL_AUTH,
236536285Sbrian  "packet filters", "set filter alive|dial|in|out rule-no permit|deny "
236681634Sbrian  "[src_addr[/width]] [dst_addr[/width]] [proto "
236748142Sbrian  "[src [lt|eq|gt port]] [dst [lt|eq|gt port]] [estab] [syn] [finrst]]"},
236836285Sbrian  {"hangup", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
236936285Sbrian  "hangup script", "set hangup chat-script", (const void *) VAR_HANGUP},
237036285Sbrian  {"ifaddr", NULL, SetInterfaceAddr, LOCAL_AUTH, "destination address",
237131343Sbrian  "set ifaddr [src-addr [dst-addr [netmask [trg-addr]]]]"},
237261534Sbrian  {"ifqueue", NULL, SetVariable, LOCAL_AUTH, "interface queue",
237361534Sbrian  "set ifqueue packets", (const void *)VAR_IFQUEUE},
237444305Sbrian  {"ipcpretry", "ipcpretries", SetVariable, LOCAL_AUTH, "IPCP retries",
237544305Sbrian   "set ipcpretry value [attempts]", (const void *)VAR_IPCPRETRY},
2376102558Sbrian  {"ipv6cpretry", "ipv6cpretries", SetVariable, LOCAL_AUTH, "IPV6CP retries",
2377102558Sbrian   "set ipv6cpretry value [attempts]", (const void *)VAR_IPV6CPRETRY},
237844305Sbrian  {"lcpretry", "lcpretries", SetVariable, LOCAL_AUTH | LOCAL_CX, "LCP retries",
237944305Sbrian   "set lcpretry value [attempts]", (const void *)VAR_LCPRETRY},
238036712Sbrian  {"log", NULL, log_SetLevel, LOCAL_AUTH, "log level",
238167916Sbrian  "set log [local] [+|-]all|async|cbcp|ccp|chat|command|connect|debug|dns|hdlc|"
2382132273Sbrian  "id0|ipcp|lcp|lqm|phase|physical|radius|sync|tcp/ip|timer|tun..."},
238336285Sbrian  {"login", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
238436285Sbrian  "login script", "set login chat-script", (const void *) VAR_LOGIN},
238552488Sbrian  {"logout", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
238652488Sbrian  "logout script", "set logout chat-script", (const void *) VAR_LOGOUT},
238736285Sbrian  {"lqrperiod", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
238836285Sbrian  "LQR period", "set lqrperiod value", (const void *)VAR_LQRPERIOD},
238936285Sbrian  {"mode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "mode value",
239036285Sbrian  "set mode interactive|auto|ddial|background", (const void *)VAR_MODE},
239136285Sbrian  {"mrru", NULL, SetVariable, LOCAL_AUTH, "MRRU value",
239236285Sbrian  "set mrru value", (const void *)VAR_MRRU},
239396038Sbrian  {"mru", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
239478410Sbrian  "MRU value", "set mru [max[imum]] [value]", (const void *)VAR_MRU},
239578410Sbrian  {"mtu", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
239678410Sbrian  "interface MTU value", "set mtu [max[imum]] [value]", (const void *)VAR_MTU},
239736285Sbrian  {"nbns", NULL, SetVariable, LOCAL_AUTH, "NetBIOS Name Server",
239836285Sbrian  "set nbns pri-addr [sec-addr]", (const void *)VAR_NBNS},
239936285Sbrian  {"openmode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "open mode",
240036285Sbrian  "set openmode active|passive [secs]", (const void *)VAR_OPENMODE},
240144305Sbrian  {"papretry", "papretries", SetVariable, LOCAL_AUTH | LOCAL_CX, "PAP retries",
240244305Sbrian   "set papretry value [attempts]", (const void *)VAR_PAPRETRY},
240346686Sbrian  {"parity", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "serial parity",
240446686Sbrian   "set parity [odd|even|none]", (const void *)VAR_PARITY},
240536285Sbrian  {"phone", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "telephone number(s)",
240636285Sbrian  "set phone phone1[:phone2[...]]", (const void *)VAR_PHONE},
240740679Sbrian  {"proctitle", "title", SetProcTitle, LOCAL_AUTH,
240840679Sbrian  "Process title", "set proctitle [value]"},
240943313Sbrian#ifndef NORADIUS
241043313Sbrian  {"radius", NULL, SetVariable, LOCAL_AUTH,
241143313Sbrian  "RADIUS Config", "set radius cfgfile", (const void *)VAR_RADIUS},
2412132273Sbrian  {"rad_alive", NULL, SetVariable, LOCAL_AUTH,
2413132273Sbrian  "Raduis alive interval", "set rad_alive value",
2414132273Sbrian  (const void *)VAR_RAD_ALIVE},
241543313Sbrian#endif
241636285Sbrian  {"reconnect", NULL, datalink_SetReconnect, LOCAL_AUTH | LOCAL_CX,
241736285Sbrian  "Reconnect timeout", "set reconnect value ntries"},
241840665Sbrian  {"recvpipe", NULL, SetVariable, LOCAL_AUTH,
241940665Sbrian  "RECVPIPE value", "set recvpipe value", (const void *)VAR_RECVPIPE},
242036285Sbrian  {"redial", NULL, datalink_SetRedial, LOCAL_AUTH | LOCAL_CX,
242144468Sbrian  "Redial timeout", "set redial secs[+inc[-incmax]][.next] [attempts]"},
242240665Sbrian  {"sendpipe", NULL, SetVariable, LOCAL_AUTH,
242340665Sbrian  "SENDPIPE value", "set sendpipe value", (const void *)VAR_SENDPIPE},
242471657Sbrian  {"server", "socket", SetServer, LOCAL_AUTH, "diagnostic port",
242571657Sbrian  "set server|socket TcpPort|LocalName|none|open|closed [password [mask]]"},
242636285Sbrian  {"speed", NULL, SetModemSpeed, LOCAL_AUTH | LOCAL_CX,
242746686Sbrian  "physical speed", "set speed value|sync"},
242836285Sbrian  {"stopped", NULL, SetStoppedTimeout, LOCAL_AUTH | LOCAL_CX,
242936285Sbrian  "STOPPED timeouts", "set stopped [LCPseconds [CCPseconds]]"},
243036285Sbrian  {"timeout", NULL, SetVariable, LOCAL_AUTH, "Idle timeout",
243136285Sbrian  "set timeout idletime", (const void *)VAR_IDLETIMEOUT},
243251048Sbrian  {"urgent", NULL, SetVariable, LOCAL_AUTH, "urgent ports",
243351048Sbrian  "set urgent [tcp|udp] [+|-]port...", (const void *)VAR_URGENTPORTS},
243436285Sbrian  {"vj", NULL, ipcp_vjset, LOCAL_AUTH,
243536285Sbrian  "vj values", "set vj slots|slotcomp [value]"},
243628679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
243731343Sbrian  "Display this message", "set help|? [command]", SetCommands},
2438132818Sglebius  {"pppoe", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
2439132818Sglebius   "Connect using standard/3Com mode", "set pppoe [standard|3Com]",
2440132818Sglebius   (const char *)VAR_PPPOE},
244128679Sbrian  {NULL, NULL, NULL},
24426059Samurai};
24436059Samurai
24446059Samuraistatic int
244531343SbrianSetCommand(struct cmdargs const *arg)
24466059Samurai{
244736285Sbrian  if (arg->argc > arg->argn)
244836285Sbrian    FindExec(arg->bundle, SetCommands, arg->argc, arg->argn, arg->argv,
244936285Sbrian             arg->prompt, arg->cx);
245036285Sbrian  else if (arg->prompt)
245136285Sbrian    prompt_Printf(arg->prompt, "Use `set ?' to get a list or `set ? <var>' for"
245258044Sbrian	          " syntax help.\n");
24536059Samurai  else
245436285Sbrian    log_Printf(LogWARN, "set command must have arguments\n");
245526516Sbrian
245626516Sbrian  return 0;
24576059Samurai}
24586059Samurai
24596059Samuraistatic int
246031343SbrianAddCommand(struct cmdargs const *arg)
24616059Samurai{
246281634Sbrian  struct ncpaddr gw;
246381634Sbrian  struct ncprange dest;
246481634Sbrian  struct in_addr host;
2465112673Sume#ifndef NOINET6
2466112673Sume  struct in6_addr host6;
2467112673Sume#endif
246881634Sbrian  int dest_default, gw_arg, addrs;
24696059Samurai
247036285Sbrian  if (arg->argc != arg->argn+3 && arg->argc != arg->argn+2)
247131598Sbrian    return -1;
247231598Sbrian
247336285Sbrian  addrs = 0;
247481634Sbrian  dest_default = 0;
247581634Sbrian  if (arg->argc == arg->argn + 2) {
247636285Sbrian    if (!strcasecmp(arg->argv[arg->argn], "default"))
247781634Sbrian      dest_default = 1;
247831598Sbrian    else {
247981634Sbrian      if (!ncprange_aton(&dest, &arg->bundle->ncp, arg->argv[arg->argn]))
248036285Sbrian        return -1;
248136285Sbrian      if (!strncasecmp(arg->argv[arg->argn], "MYADDR", 6))
248236285Sbrian        addrs = ROUTE_DSTMYADDR;
248381634Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "MYADDR6", 7))
248481634Sbrian        addrs = ROUTE_DSTMYADDR6;
248536285Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "HISADDR", 7))
248636285Sbrian        addrs = ROUTE_DSTHISADDR;
248781634Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "HISADDR6", 8))
248881634Sbrian        addrs = ROUTE_DSTHISADDR6;
248958044Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "DNS0", 4))
249058044Sbrian        addrs = ROUTE_DSTDNS0;
249158044Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "DNS1", 4))
249258044Sbrian        addrs = ROUTE_DSTDNS1;
249331598Sbrian    }
249481634Sbrian    gw_arg = 1;
249534536Sbrian  } else {
249636285Sbrian    if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
249736285Sbrian      addrs = ROUTE_DSTMYADDR;
249881634Sbrian      host = arg->bundle->ncp.ipcp.my_ip;
249936285Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
250036285Sbrian      addrs = ROUTE_DSTHISADDR;
250181634Sbrian      host = arg->bundle->ncp.ipcp.peer_ip;
250258044Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "DNS0") == 0) {
250358044Sbrian      addrs = ROUTE_DSTDNS0;
250481634Sbrian      host = arg->bundle->ncp.ipcp.ns.dns[0];
250558044Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "DNS1") == 0) {
250658044Sbrian      addrs = ROUTE_DSTDNS1;
250781634Sbrian      host = arg->bundle->ncp.ipcp.ns.dns[1];
250865263Sbrian    } else {
250981634Sbrian      host = GetIpAddr(arg->argv[arg->argn]);
251081634Sbrian      if (host.s_addr == INADDR_NONE) {
251165263Sbrian        log_Printf(LogWARN, "%s: Invalid destination address\n",
251265263Sbrian                   arg->argv[arg->argn]);
251365263Sbrian        return -1;
251465263Sbrian      }
251565263Sbrian    }
251681634Sbrian    ncprange_setip4(&dest, host, GetIpAddr(arg->argv[arg->argn + 1]));
251781634Sbrian    gw_arg = 2;
25186059Samurai  }
251936285Sbrian
252081634Sbrian  if (strcasecmp(arg->argv[arg->argn + gw_arg], "HISADDR") == 0) {
252181634Sbrian    ncpaddr_setip4(&gw, arg->bundle->ncp.ipcp.peer_ip);
252236285Sbrian    addrs |= ROUTE_GWHISADDR;
252381634Sbrian#ifndef NOINET6
252481897Sbrian  } else if (strcasecmp(arg->argv[arg->argn + gw_arg], "HISADDR6") == 0) {
2525112673Sume    if (!ncpaddr_getip6(&arg->bundle->ncp.ipv6cp.hisaddr, &host6))
2526112673Sume      memset(&host6, '\0', sizeof host6);
2527112673Sume    ncpaddr_setip6(&gw, &host6);
252881634Sbrian    addrs |= ROUTE_GWHISADDR6;
252981634Sbrian#endif
253065263Sbrian  } else {
253181634Sbrian    if (!ncpaddr_aton(&gw, &arg->bundle->ncp, arg->argv[arg->argn + gw_arg])) {
253265263Sbrian      log_Printf(LogWARN, "%s: Invalid gateway address\n",
253381634Sbrian                 arg->argv[arg->argn + gw_arg]);
253465263Sbrian      return -1;
253565263Sbrian    }
253665263Sbrian  }
253736285Sbrian
253881634Sbrian  if (dest_default)
253981634Sbrian    ncprange_setdefault(&dest, ncpaddr_family(&gw));
254081634Sbrian
254181634Sbrian  if (rt_Set(arg->bundle, RTM_ADD, &dest, &gw, arg->cmd->args ? 1 : 0,
254281634Sbrian             ((addrs & ROUTE_GWHISADDR) || (addrs & ROUTE_GWHISADDR6)) ? 1 : 0)
254343313Sbrian      && addrs != ROUTE_STATIC)
254481634Sbrian    route_Add(&arg->bundle->ncp.route, addrs, &dest, &gw);
254536285Sbrian
254631598Sbrian  return 0;
25476059Samurai}
25486059Samurai
25496059Samuraistatic int
255031343SbrianDeleteCommand(struct cmdargs const *arg)
25516059Samurai{
255281634Sbrian  struct ncprange dest;
255336285Sbrian  int addrs;
25546059Samurai
255536285Sbrian  if (arg->argc == arg->argn+1) {
255636285Sbrian    if(strcasecmp(arg->argv[arg->argn], "all") == 0) {
255736285Sbrian      route_IfDelete(arg->bundle, 0);
255881634Sbrian      route_DeleteAll(&arg->bundle->ncp.route);
255936285Sbrian    } else {
256036285Sbrian      addrs = 0;
256136285Sbrian      if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
256281634Sbrian        ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.my_ip);
256336285Sbrian        addrs = ROUTE_DSTMYADDR;
256481634Sbrian#ifndef NOINET6
256581897Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "MYADDR6") == 0) {
256681634Sbrian        ncprange_sethost(&dest, &arg->bundle->ncp.ipv6cp.myaddr);
256781634Sbrian        addrs = ROUTE_DSTMYADDR6;
256881634Sbrian#endif
256936285Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
257081634Sbrian        ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.peer_ip);
257136285Sbrian        addrs = ROUTE_DSTHISADDR;
257281634Sbrian#ifndef NOINET6
257381897Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "HISADDR6") == 0) {
257481634Sbrian        ncprange_sethost(&dest, &arg->bundle->ncp.ipv6cp.hisaddr);
257581634Sbrian        addrs = ROUTE_DSTHISADDR6;
257681634Sbrian#endif
257758044Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "DNS0") == 0) {
257881634Sbrian        ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.ns.dns[0]);
257958044Sbrian        addrs = ROUTE_DSTDNS0;
258058044Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "DNS1") == 0) {
258181634Sbrian        ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.ns.dns[1]);
258258044Sbrian        addrs = ROUTE_DSTDNS1;
258336285Sbrian      } else {
258481634Sbrian        ncprange_aton(&dest, &arg->bundle->ncp, arg->argv[arg->argn]);
258536285Sbrian        addrs = ROUTE_STATIC;
258636285Sbrian      }
258781634Sbrian      rt_Set(arg->bundle, RTM_DELETE, &dest, NULL, arg->cmd->args ? 1 : 0, 0);
258881634Sbrian      route_Delete(&arg->bundle->ncp.route, addrs, &dest);
258931598Sbrian    }
259034536Sbrian  } else
259126516Sbrian    return -1;
259226516Sbrian
259326516Sbrian  return 0;
25946059Samurai}
25956059Samurai
259650059Sbrian#ifndef NONAT
259726031Sbrianstatic int
259858867SbrianNatEnable(struct cmdargs const *arg)
259926031Sbrian{
260036285Sbrian  if (arg->argc == arg->argn+1) {
260136285Sbrian    if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
260250059Sbrian      if (!arg->bundle->NatEnabled) {
260346686Sbrian        if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED)
260446686Sbrian          PacketAliasSetAddress(arg->bundle->ncp.ipcp.my_ip);
260550059Sbrian        arg->bundle->NatEnabled = 1;
260646686Sbrian      }
260737191Sbrian      return 0;
260836285Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "no") == 0) {
260950059Sbrian      arg->bundle->NatEnabled = 0;
261040561Sbrian      arg->bundle->cfg.opt &= ~OPT_IFACEALIAS;
261140561Sbrian      /* Don't iface_Clear() - there may be manually configured addresses */
261226516Sbrian      return 0;
261326142Sbrian    }
261435449Sbrian  }
261536285Sbrian
261626516Sbrian  return -1;
261726031Sbrian}
261826031Sbrian
261926031Sbrian
262026031Sbrianstatic int
262158867SbrianNatOption(struct cmdargs const *arg)
262226031Sbrian{
262338559Sbrian  long param = (long)arg->cmd->args;
262438559Sbrian
262536285Sbrian  if (arg->argc == arg->argn+1) {
262636285Sbrian    if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
262750059Sbrian      if (arg->bundle->NatEnabled) {
262837191Sbrian	PacketAliasSetMode(param, param);
262928679Sbrian	return 0;
263028679Sbrian      }
263150059Sbrian      log_Printf(LogWARN, "nat not enabled\n");
263236285Sbrian    } else if (strcmp(arg->argv[arg->argn], "no") == 0) {
263350059Sbrian      if (arg->bundle->NatEnabled) {
263437191Sbrian	PacketAliasSetMode(0, param);
263528679Sbrian	return 0;
263628679Sbrian      }
263750059Sbrian      log_Printf(LogWARN, "nat not enabled\n");
263828679Sbrian    }
263935449Sbrian  }
264028679Sbrian  return -1;
264126031Sbrian}
264250059Sbrian#endif /* #ifndef NONAT */
264331121Sbrian
264431121Sbrianstatic int
264536285SbrianLinkCommand(struct cmdargs const *arg)
264636285Sbrian{
264736285Sbrian  if (arg->argc > arg->argn+1) {
264836285Sbrian    char namelist[LINE_LEN];
264936285Sbrian    struct datalink *cx;
265036285Sbrian    char *name;
265136285Sbrian    int result = 0;
265236285Sbrian
265336285Sbrian    if (!strcmp(arg->argv[arg->argn], "*")) {
265436285Sbrian      struct datalink *dl;
265536285Sbrian
265636285Sbrian      cx = arg->bundle->links;
265736285Sbrian      while (cx) {
265836285Sbrian        /* Watch it, the command could be a ``remove'' */
265936285Sbrian        dl = cx->next;
266036285Sbrian        FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
266136285Sbrian                 arg->prompt, cx);
266236285Sbrian        for (cx = arg->bundle->links; cx; cx = cx->next)
266336285Sbrian          if (cx == dl)
266436285Sbrian            break;		/* Pointer's still valid ! */
266536285Sbrian      }
266636285Sbrian    } else {
266736285Sbrian      strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
266836285Sbrian      namelist[sizeof namelist - 1] = '\0';
266936285Sbrian      for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
267036285Sbrian        if (!bundle2datalink(arg->bundle, name)) {
267136285Sbrian          log_Printf(LogWARN, "link: %s: Invalid link name\n", name);
267236285Sbrian          return 1;
267336285Sbrian        }
267436285Sbrian
267536285Sbrian      strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
267636285Sbrian      namelist[sizeof namelist - 1] = '\0';
267736285Sbrian      for(name = strtok(namelist, ", "); name; name = strtok(NULL,", ")) {
267836285Sbrian        cx = bundle2datalink(arg->bundle, name);
267936285Sbrian        if (cx)
268036285Sbrian          FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
268136285Sbrian                   arg->prompt, cx);
268236285Sbrian        else {
268336285Sbrian          log_Printf(LogWARN, "link: %s: Invalidated link name !\n", name);
268436285Sbrian          result++;
268536285Sbrian        }
268636285Sbrian      }
268736285Sbrian    }
268836285Sbrian    return result;
268936285Sbrian  }
269036285Sbrian
269195258Sdes  log_Printf(LogWARN, "usage: %s\n", arg->cmd->syntax);
269236285Sbrian  return 2;
269336285Sbrian}
269436285Sbrian
269536285Sbrianstruct link *
269636285Sbriancommand_ChooseLink(struct cmdargs const *arg)
269736285Sbrian{
269836285Sbrian  if (arg->cx)
269936285Sbrian    return &arg->cx->physical->link;
270037210Sbrian  else if (!arg->bundle->ncp.mp.cfg.mrru) {
270136285Sbrian    struct datalink *dl = bundle2datalink(arg->bundle, NULL);
270237210Sbrian    if (dl)
270337210Sbrian      return &dl->physical->link;
270436285Sbrian  }
270537210Sbrian  return &arg->bundle->ncp.mp.link;
270636285Sbrian}
270736285Sbrian
270836285Sbrianstatic const char *
270936285Sbrianident_cmd(const char *cmd, unsigned *keep, unsigned *add)
271036285Sbrian{
271136285Sbrian  const char *result;
271236285Sbrian
271336285Sbrian  switch (*cmd) {
271436285Sbrian    case 'A':
271536285Sbrian    case 'a':
271636285Sbrian      result = "accept";
271736285Sbrian      *keep = NEG_MYMASK;
271836285Sbrian      *add = NEG_ACCEPTED;
271936285Sbrian      break;
272036285Sbrian    case 'D':
272136285Sbrian    case 'd':
272236285Sbrian      switch (cmd[1]) {
272336285Sbrian        case 'E':
272436285Sbrian        case 'e':
272536285Sbrian          result = "deny";
272636285Sbrian          *keep = NEG_MYMASK;
272736285Sbrian          *add = 0;
272836285Sbrian          break;
272936285Sbrian        case 'I':
273036285Sbrian        case 'i':
273136285Sbrian          result = "disable";
273236285Sbrian          *keep = NEG_HISMASK;
273336285Sbrian          *add = 0;
273436285Sbrian          break;
273536285Sbrian        default:
273636285Sbrian          return NULL;
273736285Sbrian      }
273836285Sbrian      break;
273936285Sbrian    case 'E':
274036285Sbrian    case 'e':
274136285Sbrian      result = "enable";
274236285Sbrian      *keep = NEG_HISMASK;
274336285Sbrian      *add = NEG_ENABLED;
274436285Sbrian      break;
274536285Sbrian    default:
274636285Sbrian      return NULL;
274736285Sbrian  }
274836285Sbrian
274936285Sbrian  return result;
275036285Sbrian}
275136285Sbrian
275236285Sbrianstatic int
275336285SbrianOptSet(struct cmdargs const *arg)
275436285Sbrian{
275537574Sbrian  int bit = (int)(long)arg->cmd->args;
275636285Sbrian  unsigned keep;			/* Keep these bits */
275736285Sbrian  unsigned add;				/* Add these bits */
275836285Sbrian
275981697Sbrian  if (ident_cmd(arg->argv[arg->argn - 2], &keep, &add) == NULL)
276036285Sbrian    return 1;
276136285Sbrian
276281885Sbrian#ifndef NOINET6
276381697Sbrian  if (add == NEG_ENABLED && bit == OPT_IPV6CP && !probe.ipv6_available) {
276481697Sbrian    log_Printf(LogWARN, "IPv6 is not available on this machine\n");
276581697Sbrian    return 1;
276681697Sbrian  }
276781885Sbrian#endif
276881697Sbrian
276936285Sbrian  if (add)
277036285Sbrian    arg->bundle->cfg.opt |= bit;
277136285Sbrian  else
277236285Sbrian    arg->bundle->cfg.opt &= ~bit;
277381697Sbrian
277436285Sbrian  return 0;
277536285Sbrian}
277636285Sbrian
277736285Sbrianstatic int
277840561SbrianIfaceAliasOptSet(struct cmdargs const *arg)
277940561Sbrian{
278040561Sbrian  unsigned save = arg->bundle->cfg.opt;
278140561Sbrian  int result = OptSet(arg);
278240561Sbrian
278340561Sbrian  if (result == 0)
278450059Sbrian    if (Enabled(arg->bundle, OPT_IFACEALIAS) && !arg->bundle->NatEnabled) {
278540561Sbrian      arg->bundle->cfg.opt = save;
278650059Sbrian      log_Printf(LogWARN, "Cannot enable iface-alias without NAT\n");
278740561Sbrian      result = 2;
278840561Sbrian    }
278940561Sbrian
279040561Sbrian  return result;
279140561Sbrian}
279240561Sbrian
279340561Sbrianstatic int
279436285SbrianNegotiateSet(struct cmdargs const *arg)
279536285Sbrian{
279637210Sbrian  long param = (long)arg->cmd->args;
279736285Sbrian  struct link *l = command_ChooseLink(arg);	/* LOCAL_CX_OPT uses this */
279836285Sbrian  struct datalink *cx = arg->cx;	/* LOCAL_CX uses this */
279936285Sbrian  const char *cmd;
280036285Sbrian  unsigned keep;			/* Keep these bits */
280136285Sbrian  unsigned add;				/* Add these bits */
280236285Sbrian
280336285Sbrian  if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL)
280436285Sbrian    return 1;
280536285Sbrian
280636285Sbrian  if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
280736285Sbrian    log_Printf(LogWARN, "%s %s: No context (use the `link' command)\n",
280836285Sbrian              cmd, arg->cmd->name);
280936285Sbrian    return 2;
281036285Sbrian  } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
281136285Sbrian    log_Printf(LogWARN, "%s %s: Redundant context (%s) ignored\n",
281236285Sbrian              cmd, arg->cmd->name, cx->name);
281336285Sbrian    cx = NULL;
281436285Sbrian  }
281536285Sbrian
281636285Sbrian  switch (param) {
281736285Sbrian    case NEG_ACFCOMP:
281836285Sbrian      cx->physical->link.lcp.cfg.acfcomp &= keep;
281936285Sbrian      cx->physical->link.lcp.cfg.acfcomp |= add;
282036285Sbrian      break;
282144106Sbrian    case NEG_CHAP05:
282244106Sbrian      cx->physical->link.lcp.cfg.chap05 &= keep;
282344106Sbrian      cx->physical->link.lcp.cfg.chap05 |= add;
282436285Sbrian      break;
282593418Sbrian#ifndef NODES
282644106Sbrian    case NEG_CHAP80:
282744106Sbrian      cx->physical->link.lcp.cfg.chap80nt &= keep;
282844106Sbrian      cx->physical->link.lcp.cfg.chap80nt |= add;
282944106Sbrian      break;
283044106Sbrian    case NEG_CHAP80LM:
283144106Sbrian      cx->physical->link.lcp.cfg.chap80lm &= keep;
283244106Sbrian      cx->physical->link.lcp.cfg.chap80lm |= add;
283344106Sbrian      break;
283467910Sbrian    case NEG_CHAP81:
283567910Sbrian      cx->physical->link.lcp.cfg.chap81 &= keep;
283667910Sbrian      cx->physical->link.lcp.cfg.chap81 |= add;
283767910Sbrian      break;
283867910Sbrian    case NEG_MPPE:
283967910Sbrian      l->ccp.cfg.neg[CCP_NEG_MPPE] &= keep;
284067910Sbrian      l->ccp.cfg.neg[CCP_NEG_MPPE] |= add;
284167910Sbrian      break;
284244106Sbrian#endif
284336285Sbrian    case NEG_DEFLATE:
284436285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE] &= keep;
284536285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE] |= add;
284636285Sbrian      break;
284736285Sbrian    case NEG_DNS:
284836285Sbrian      arg->bundle->ncp.ipcp.cfg.ns.dns_neg &= keep;
284936285Sbrian      arg->bundle->ncp.ipcp.cfg.ns.dns_neg |= add;
285036285Sbrian      break;
285147858Sbrian    case NEG_ENDDISC:
285247858Sbrian      arg->bundle->ncp.mp.cfg.negenddisc &= keep;
285347858Sbrian      arg->bundle->ncp.mp.cfg.negenddisc |= add;
285447858Sbrian      break;
285536285Sbrian    case NEG_LQR:
285636285Sbrian      cx->physical->link.lcp.cfg.lqr &= keep;
285736285Sbrian      cx->physical->link.lcp.cfg.lqr |= add;
285836285Sbrian      break;
285936285Sbrian    case NEG_PAP:
286036285Sbrian      cx->physical->link.lcp.cfg.pap &= keep;
286136285Sbrian      cx->physical->link.lcp.cfg.pap |= add;
286236285Sbrian      break;
286336285Sbrian    case NEG_PPPDDEFLATE:
286436285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE24] &= keep;
286536285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE24] |= add;
286636285Sbrian      break;
286736285Sbrian    case NEG_PRED1:
286836285Sbrian      l->ccp.cfg.neg[CCP_NEG_PRED1] &= keep;
286936285Sbrian      l->ccp.cfg.neg[CCP_NEG_PRED1] |= add;
287036285Sbrian      break;
287136285Sbrian    case NEG_PROTOCOMP:
287236285Sbrian      cx->physical->link.lcp.cfg.protocomp &= keep;
287336285Sbrian      cx->physical->link.lcp.cfg.protocomp |= add;
287436285Sbrian      break;
287536285Sbrian    case NEG_SHORTSEQ:
287640622Sbrian      switch (bundle_Phase(arg->bundle)) {
287740622Sbrian        case PHASE_DEAD:
287840622Sbrian          break;
287940622Sbrian        case PHASE_ESTABLISH:
288040622Sbrian          /* Make sure none of our links are DATALINK_LCP or greater */
288140622Sbrian          if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) {
288240622Sbrian            log_Printf(LogWARN, "shortseq: Only changable before"
288340622Sbrian                       " LCP negotiations\n");
288440622Sbrian            return 1;
288540622Sbrian          }
288640622Sbrian          break;
288740622Sbrian        default:
288840622Sbrian          log_Printf(LogWARN, "shortseq: Only changable at phase"
288940622Sbrian                     " DEAD/ESTABLISH\n");
289040622Sbrian          return 1;
289136285Sbrian      }
289240622Sbrian      arg->bundle->ncp.mp.cfg.shortseq &= keep;
289340622Sbrian      arg->bundle->ncp.mp.cfg.shortseq |= add;
289436285Sbrian      break;
289536285Sbrian    case NEG_VJCOMP:
289636285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.neg &= keep;
289736285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.neg |= add;
289836285Sbrian      break;
289936285Sbrian  }
290036285Sbrian
290136285Sbrian  return 0;
290236285Sbrian}
290336285Sbrian
290436285Sbrianstatic struct cmdtab const NegotiateCommands[] = {
290562778Sbrian  {"filter-decapsulation", NULL, OptSet, LOCAL_AUTH,
290662778Sbrian  "filter on PPPoUDP payloads", "disable|enable",
290762778Sbrian  (const void *)OPT_FILTERDECAP},
2908112659Sbrian  {"force-scripts", NULL, OptSet, LOCAL_AUTH,
2909112659Sbrian   "Force execution of the configured chat scripts", "disable|enable",
2910112659Sbrian   (const void *)OPT_FORCE_SCRIPTS},
291136285Sbrian  {"idcheck", NULL, OptSet, LOCAL_AUTH, "Check FSM reply ids",
291236285Sbrian  "disable|enable", (const void *)OPT_IDCHECK},
291340666Sbrian  {"iface-alias", NULL, IfaceAliasOptSet, LOCAL_AUTH,
291462778Sbrian  "retain interface addresses", "disable|enable",
291562778Sbrian  (const void *)OPT_IFACEALIAS},
291681634Sbrian#ifndef NOINET6
291781634Sbrian  {"ipcp", NULL, OptSet, LOCAL_AUTH, "IP Network Control Protocol",
291881634Sbrian  "disable|enable", (const void *)OPT_IPCP},
291981634Sbrian  {"ipv6cp", NULL, OptSet, LOCAL_AUTH, "IPv6 Network Control Protocol",
292081634Sbrian  "disable|enable", (const void *)OPT_IPV6CP},
292181634Sbrian#endif
292247689Sbrian  {"keep-session", NULL, OptSet, LOCAL_AUTH, "Retain device session leader",
292347689Sbrian  "disable|enable", (const void *)OPT_KEEPSESSION},
292436285Sbrian  {"loopback", NULL, OptSet, LOCAL_AUTH, "Loop packets for local iface",
292536285Sbrian  "disable|enable", (const void *)OPT_LOOPBACK},
292636285Sbrian  {"passwdauth", NULL, OptSet, LOCAL_AUTH, "Use passwd file",
292736285Sbrian  "disable|enable", (const void *)OPT_PASSWDAUTH},
292840665Sbrian  {"proxy", NULL, OptSet, LOCAL_AUTH, "Create a proxy ARP entry",
292936285Sbrian  "disable|enable", (const void *)OPT_PROXY},
293040665Sbrian  {"proxyall", NULL, OptSet, LOCAL_AUTH, "Proxy ARP for all remote hosts",
293140665Sbrian  "disable|enable", (const void *)OPT_PROXYALL},
293236285Sbrian  {"sroutes", NULL, OptSet, LOCAL_AUTH, "Use sticky routes",
293336285Sbrian  "disable|enable", (const void *)OPT_SROUTES},
293469303Sbrian  {"tcpmssfixup", "mssfixup", OptSet, LOCAL_AUTH, "Modify MSS options",
293569303Sbrian  "disable|enable", (const void *)OPT_TCPMSSFIXUP},
293636285Sbrian  {"throughput", NULL, OptSet, LOCAL_AUTH, "Rolling throughput",
293736285Sbrian  "disable|enable", (const void *)OPT_THROUGHPUT},
293836285Sbrian  {"utmp", NULL, OptSet, LOCAL_AUTH, "Log connections in utmp",
293936285Sbrian  "disable|enable", (const void *)OPT_UTMP},
294036285Sbrian
294181634Sbrian#ifndef NOINET6
2942112659Sbrian#define OPT_MAX 14	/* accept/deny allowed below and not above */
294381634Sbrian#else
2944112659Sbrian#define OPT_MAX 12
294581634Sbrian#endif
294636285Sbrian
294736285Sbrian  {"acfcomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
294836285Sbrian  "Address & Control field compression", "accept|deny|disable|enable",
294936285Sbrian  (const void *)NEG_ACFCOMP},
295044106Sbrian  {"chap", "chap05", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
295136285Sbrian  "Challenge Handshake Authentication Protocol", "accept|deny|disable|enable",
295244106Sbrian  (const void *)NEG_CHAP05},
295393418Sbrian#ifndef NODES
295444106Sbrian  {"mschap", "chap80nt", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
295544106Sbrian  "Microsoft (NT) CHAP", "accept|deny|disable|enable",
295644106Sbrian  (const void *)NEG_CHAP80},
295744106Sbrian  {"LANMan", "chap80lm", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
295844106Sbrian  "Microsoft (NT) CHAP", "accept|deny|disable|enable",
295944106Sbrian  (const void *)NEG_CHAP80LM},
296067910Sbrian  {"mschapv2", "chap81", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
296167910Sbrian  "Microsoft CHAP v2", "accept|deny|disable|enable",
296267910Sbrian  (const void *)NEG_CHAP81},
296367910Sbrian  {"mppe", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
296467910Sbrian  "MPPE encryption", "accept|deny|disable|enable",
296567910Sbrian  (const void *)NEG_MPPE},
296644106Sbrian#endif
296736285Sbrian  {"deflate", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
296836285Sbrian  "Deflate compression", "accept|deny|disable|enable",
296936285Sbrian  (const void *)NEG_DEFLATE},
297036285Sbrian  {"deflate24", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
297136285Sbrian  "Deflate (type 24) compression", "accept|deny|disable|enable",
297236285Sbrian  (const void *)NEG_PPPDDEFLATE},
297336285Sbrian  {"dns", NULL, NegotiateSet, LOCAL_AUTH,
297436285Sbrian  "DNS specification", "accept|deny|disable|enable", (const void *)NEG_DNS},
297547858Sbrian  {"enddisc", NULL, NegotiateSet, LOCAL_AUTH, "ENDDISC negotiation",
297647858Sbrian  "accept|deny|disable|enable", (const void *)NEG_ENDDISC},
297736285Sbrian  {"lqr", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
297836285Sbrian  "Link Quality Reports", "accept|deny|disable|enable",
297936285Sbrian  (const void *)NEG_LQR},
298036285Sbrian  {"pap", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
298136285Sbrian  "Password Authentication protocol", "accept|deny|disable|enable",
298236285Sbrian  (const void *)NEG_PAP},
298336285Sbrian  {"pred1", "predictor1", NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
298436285Sbrian  "Predictor 1 compression", "accept|deny|disable|enable",
298536285Sbrian  (const void *)NEG_PRED1},
298636285Sbrian  {"protocomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
298736285Sbrian  "Protocol field compression", "accept|deny|disable|enable",
298836285Sbrian  (const void *)NEG_PROTOCOMP},
298936285Sbrian  {"shortseq", NULL, NegotiateSet, LOCAL_AUTH,
299036285Sbrian  "MP Short Sequence Numbers", "accept|deny|disable|enable",
299136285Sbrian  (const void *)NEG_SHORTSEQ},
299236285Sbrian  {"vjcomp", NULL, NegotiateSet, LOCAL_AUTH,
299336285Sbrian  "Van Jacobson header compression", "accept|deny|disable|enable",
299436285Sbrian  (const void *)NEG_VJCOMP},
299536285Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
299636285Sbrian  "Display this message", "accept|deny|disable|enable help|? [value]",
299736285Sbrian  NegotiateCommands},
299836285Sbrian  {NULL, NULL, NULL},
299936285Sbrian};
300036285Sbrian
300136285Sbrianstatic int
300236285SbrianNegotiateCommand(struct cmdargs const *arg)
300336285Sbrian{
300436285Sbrian  if (arg->argc > arg->argn) {
300536285Sbrian    char const *argv[3];
300636285Sbrian    unsigned keep, add;
300736285Sbrian    int n;
300836285Sbrian
300936285Sbrian    if ((argv[0] = ident_cmd(arg->argv[arg->argn-1], &keep, &add)) == NULL)
301036285Sbrian      return -1;
301136285Sbrian    argv[2] = NULL;
301236285Sbrian
301336285Sbrian    for (n = arg->argn; n < arg->argc; n++) {
301436285Sbrian      argv[1] = arg->argv[n];
301536285Sbrian      FindExec(arg->bundle, NegotiateCommands + (keep == NEG_HISMASK ?
301636285Sbrian               0 : OPT_MAX), 2, 1, argv, arg->prompt, arg->cx);
301736285Sbrian    }
301836285Sbrian  } else if (arg->prompt)
301936285Sbrian    prompt_Printf(arg->prompt, "Use `%s ?' to get a list.\n",
302036285Sbrian	    arg->argv[arg->argn-1]);
302136285Sbrian  else
302236285Sbrian    log_Printf(LogWARN, "%s command must have arguments\n",
302336285Sbrian              arg->argv[arg->argn] );
302436285Sbrian
302536285Sbrian  return 0;
302636285Sbrian}
302736285Sbrian
302836285Sbrianconst char *
302936285Sbriancommand_ShowNegval(unsigned val)
303036285Sbrian{
303136285Sbrian  switch (val&3) {
303236285Sbrian    case 1: return "disabled & accepted";
303336285Sbrian    case 2: return "enabled & denied";
303436285Sbrian    case 3: return "enabled & accepted";
303536285Sbrian  }
303636285Sbrian  return "disabled & denied";
303736285Sbrian}
303836934Sbrian
303936934Sbrianstatic int
304036934SbrianClearCommand(struct cmdargs const *arg)
304136934Sbrian{
304236934Sbrian  struct pppThroughput *t;
304336934Sbrian  struct datalink *cx;
304436934Sbrian  int i, clear_type;
304536934Sbrian
304636934Sbrian  if (arg->argc < arg->argn + 1)
304736934Sbrian    return -1;
304836934Sbrian
304946686Sbrian  if (strcasecmp(arg->argv[arg->argn], "physical") == 0) {
305036934Sbrian    cx = arg->cx;
305136934Sbrian    if (!cx)
305236934Sbrian      cx = bundle2datalink(arg->bundle, NULL);
305336934Sbrian    if (!cx) {
305446686Sbrian      log_Printf(LogWARN, "A link must be specified for ``clear physical''\n");
305536934Sbrian      return 1;
305636934Sbrian    }
305764652Sbrian    t = &cx->physical->link.stats.total;
305836934Sbrian  } else if (strcasecmp(arg->argv[arg->argn], "ipcp") == 0)
305936934Sbrian    t = &arg->bundle->ncp.ipcp.throughput;
306081634Sbrian#ifndef NOINET6
306181897Sbrian  else if (strcasecmp(arg->argv[arg->argn], "ipv6cp") == 0)
306281634Sbrian    t = &arg->bundle->ncp.ipv6cp.throughput;
306381634Sbrian#endif
306436934Sbrian  else
306536934Sbrian    return -1;
306636934Sbrian
306736934Sbrian  if (arg->argc > arg->argn + 1) {
306836934Sbrian    clear_type = 0;
306936934Sbrian    for (i = arg->argn + 1; i < arg->argc; i++)
307036934Sbrian      if (strcasecmp(arg->argv[i], "overall") == 0)
307136934Sbrian        clear_type |= THROUGHPUT_OVERALL;
307236934Sbrian      else if (strcasecmp(arg->argv[i], "current") == 0)
307336934Sbrian        clear_type |= THROUGHPUT_CURRENT;
307436934Sbrian      else if (strcasecmp(arg->argv[i], "peak") == 0)
307536934Sbrian        clear_type |= THROUGHPUT_PEAK;
307636934Sbrian      else
307736934Sbrian        return -1;
307898243Sbrian  } else
307936934Sbrian    clear_type = THROUGHPUT_ALL;
308036934Sbrian
308136934Sbrian  throughput_clear(t, clear_type, arg->prompt);
308236934Sbrian  return 0;
308336934Sbrian}
308440561Sbrian
308540561Sbrianstatic int
308640561SbrianRunListCommand(struct cmdargs const *arg)
308740561Sbrian{
308840561Sbrian  const char *cmd = arg->argc ? arg->argv[arg->argc - 1] : "???";
308940561Sbrian
309064801Sbrian#ifndef NONAT
309164801Sbrian  if (arg->cmd->args == NatCommands &&
309264801Sbrian      tolower(*arg->argv[arg->argn - 1]) == 'a') {
309364801Sbrian    if (arg->prompt)
309465550Sbrian      prompt_Printf(arg->prompt, "The alias command is deprecated\n");
309564801Sbrian    else
309665550Sbrian      log_Printf(LogWARN, "The alias command is deprecated\n");
309764801Sbrian  }
309864801Sbrian#endif
309964801Sbrian
310040561Sbrian  if (arg->argc > arg->argn)
310140561Sbrian    FindExec(arg->bundle, arg->cmd->args, arg->argc, arg->argn, arg->argv,
310240561Sbrian             arg->prompt, arg->cx);
310340561Sbrian  else if (arg->prompt)
310440561Sbrian    prompt_Printf(arg->prompt, "Use `%s help' to get a list or `%s help"
310540561Sbrian                  " <option>' for syntax help.\n", cmd, cmd);
310640561Sbrian  else
310740561Sbrian    log_Printf(LogWARN, "%s command must have arguments\n", cmd);
310840561Sbrian
310940561Sbrian  return 0;
311040561Sbrian}
311140561Sbrian
311240561Sbrianstatic int
311340561SbrianIfaceAddCommand(struct cmdargs const *arg)
311440561Sbrian{
311581634Sbrian  struct ncpaddr peer, addr;
311681634Sbrian  struct ncprange ifa;
311781634Sbrian  struct in_addr mask;
311881634Sbrian  int n, how;
311940561Sbrian
312040664Sbrian  if (arg->argc == arg->argn + 1) {
312181634Sbrian    if (!ncprange_aton(&ifa, NULL, arg->argv[arg->argn]))
312240561Sbrian      return -1;
312381634Sbrian    ncpaddr_init(&peer);
312440664Sbrian  } else {
312540664Sbrian    if (arg->argc == arg->argn + 2) {
312681634Sbrian      if (!ncprange_aton(&ifa, NULL, arg->argv[arg->argn]))
312740664Sbrian        return -1;
312840664Sbrian      n = 1;
312940664Sbrian    } else if (arg->argc == arg->argn + 3) {
313081634Sbrian      if (!ncpaddr_aton(&addr, NULL, arg->argv[arg->argn]))
313140664Sbrian        return -1;
313281634Sbrian      if (ncpaddr_family(&addr) != AF_INET)
313340664Sbrian        return -1;
313481634Sbrian      ncprange_sethost(&ifa, &addr);
313581634Sbrian      if (!ncpaddr_aton(&addr, NULL, arg->argv[arg->argn + 1]))
313681634Sbrian        return -1;
313781634Sbrian      if (!ncpaddr_getip4(&addr, &mask))
313881634Sbrian        return -1;
313981634Sbrian      if (!ncprange_setip4mask(&ifa, mask))
314081634Sbrian        return -1;
314140664Sbrian      n = 2;
314240664Sbrian    } else
314340561Sbrian      return -1;
314440561Sbrian
314581634Sbrian    if (!ncpaddr_aton(&peer, NULL, arg->argv[arg->argn + n]))
314640664Sbrian      return -1;
314781634Sbrian
314881634Sbrian    if (ncprange_family(&ifa) != ncpaddr_family(&peer)) {
314981634Sbrian      log_Printf(LogWARN, "IfaceAddCommand: src and dst address families"
315081634Sbrian                 " differ\n");
315181634Sbrian      return -1;
315281634Sbrian    }
315340664Sbrian  }
315440561Sbrian
315540561Sbrian  how = IFACE_ADD_LAST;
315640561Sbrian  if (arg->cmd->args)
315740561Sbrian    how |= IFACE_FORCE_ADD;
315840561Sbrian
315981634Sbrian  return !iface_Add(arg->bundle->iface, &arg->bundle->ncp, &ifa, &peer, how);
316040561Sbrian}
316140561Sbrian
316240561Sbrianstatic int
316340561SbrianIfaceDeleteCommand(struct cmdargs const *arg)
316440561Sbrian{
316581634Sbrian  struct ncpaddr ifa;
316681634Sbrian  struct in_addr ifa4;
316740561Sbrian  int ok;
316840561Sbrian
316940561Sbrian  if (arg->argc != arg->argn + 1)
317040561Sbrian    return -1;
317140561Sbrian
317281634Sbrian  if (!ncpaddr_aton(&ifa, NULL, arg->argv[arg->argn]))
317340561Sbrian    return -1;
317440561Sbrian
317540561Sbrian  if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED &&
317681634Sbrian      ncpaddr_getip4(&ifa, &ifa4) &&
317781634Sbrian      arg->bundle->ncp.ipcp.my_ip.s_addr == ifa4.s_addr) {
317840561Sbrian    log_Printf(LogWARN, "%s: Cannot remove active interface address\n",
317981634Sbrian               ncpaddr_ntoa(&ifa));
318040561Sbrian    return 1;
318140561Sbrian  }
318240561Sbrian
318381634Sbrian  ok = iface_Delete(arg->bundle->iface, &arg->bundle->ncp, &ifa);
318440561Sbrian  if (!ok) {
318540561Sbrian    if (arg->cmd->args)
318640561Sbrian      ok = 1;
318740561Sbrian    else if (arg->prompt)
318881634Sbrian      prompt_Printf(arg->prompt, "%s: No such interface address\n",
318981634Sbrian                    ncpaddr_ntoa(&ifa));
319040561Sbrian    else
319181634Sbrian      log_Printf(LogWARN, "%s: No such interface address\n",
319281634Sbrian                 ncpaddr_ntoa(&ifa));
319340561Sbrian  }
319440561Sbrian
319540561Sbrian  return !ok;
319640561Sbrian}
319740561Sbrian
319840561Sbrianstatic int
319940561SbrianIfaceClearCommand(struct cmdargs const *arg)
320040561Sbrian{
320181634Sbrian  int family, how;
320240561Sbrian
320381634Sbrian  family = 0;
320481634Sbrian  if (arg->argc == arg->argn + 1) {
320581634Sbrian    if (strcasecmp(arg->argv[arg->argn], "inet") == 0)
320681634Sbrian      family = AF_INET;
320781634Sbrian#ifndef NOINET6
320881897Sbrian    else if (strcasecmp(arg->argv[arg->argn], "inet6") == 0)
320981634Sbrian      family = AF_INET6;
321081634Sbrian#endif
321181634Sbrian    else
321281634Sbrian      return -1;
321381634Sbrian  } else if (arg->argc != arg->argn)
321440561Sbrian    return -1;
321540561Sbrian
321640941Sbrian  how = arg->bundle->ncp.ipcp.fsm.state == ST_OPENED ||
321740941Sbrian        arg->bundle->phys_type.all & PHYS_AUTO ?
321840561Sbrian        IFACE_CLEAR_ALIASES : IFACE_CLEAR_ALL;
321981634Sbrian  iface_Clear(arg->bundle->iface, &arg->bundle->ncp, family, how);
322040561Sbrian
322140561Sbrian  return 0;
322240561Sbrian}
322340679Sbrian
322440679Sbrianstatic int
322540679SbrianSetProcTitle(struct cmdargs const *arg)
322640679Sbrian{
322740679Sbrian  static char title[LINE_LEN];
322886028Sbrian  char *argv[MAXARGS];
322986028Sbrian  int argc = arg->argc - arg->argn;
323040679Sbrian
323140679Sbrian  if (arg->argc == arg->argn) {
323264698Sbrian    SetTitle(NULL);
323340679Sbrian    return 0;
323440679Sbrian  }
323540679Sbrian
323640679Sbrian  if (argc >= sizeof argv / sizeof argv[0]) {
323740679Sbrian    argc = sizeof argv / sizeof argv[0] - 1;
323840679Sbrian    log_Printf(LogWARN, "Truncating proc title to %d args\n", argc);
323940679Sbrian  }
324047849Sbrian  command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 1, getpid());
324185991Sbrian  Concatinate(title, sizeof title, argc, (const char *const *)argv);
324264698Sbrian  SetTitle(title);
324385991Sbrian  command_Free(argc, argv);
324440679Sbrian
324540679Sbrian  return 0;
324640679Sbrian}
3247