command.c revision 134789
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 134789 2004-09-05 01:46:52Z brian $
296059Samurai */
3078189Sbrian
3143313Sbrian#include <sys/param.h>
3230715Sbrian#include <netinet/in_systm.h>
3326031Sbrian#include <netinet/in.h>
3430715Sbrian#include <netinet/ip.h>
3526031Sbrian#include <arpa/inet.h>
3630715Sbrian#include <sys/socket.h>
3726031Sbrian#include <net/route.h>
3830715Sbrian#include <netdb.h>
3936285Sbrian#include <sys/un.h>
4030715Sbrian
4138628Sbrian#include <ctype.h>
4230715Sbrian#include <errno.h>
4326516Sbrian#include <fcntl.h>
4430715Sbrian#include <paths.h>
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
170134789Sbrianconst char Version[] = "3.3";
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
367134789Sbrian    if (argc >= (int)(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
382134789SbrianSaveCommand(struct cmdargs const *arg __unused)
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
676134789Sbrian      if (argc >= (int)(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,
759134789Sbrian   "static address translation", "nat addr [addr_local addr_alias]", NULL},
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,
764134789Sbrian   "enable NAT", "nat enable yes|no", NULL},
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",
769134789Sbrian   "nat port proto localaddr:port[-port] aliasport[-aliasport]", NULL},
77079433Sbrian  {"proto", NULL, nat_RedirectProto, LOCAL_AUTH, "protocol redirection",
771134789Sbrian   "nat proto proto localIP [publicIP [remoteIP]]", NULL},
77250059Sbrian  {"proxy", NULL, nat_ProxyRule, LOCAL_AUTH,
773134789Sbrian   "proxy control", "nat proxy server host[:port] ...", NULL},
77481033Sbrian#ifndef NO_FW_PUNCH
77581033Sbrian  {"punch_fw", NULL, nat_PunchFW, LOCAL_AUTH,
776134789Sbrian   "firewall control", "nat punch_fw [base count]", NULL},
77781033Sbrian#endif
778120372Smarcus  {"skinny_port", NULL, nat_SkinnyPort, LOCAL_AUTH,
779134789Sbrian   "TCP port used by Skinny Station protocol", "nat skinny_port [port]", NULL},
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,
784134789Sbrian   "Default address for incoming connections", "nat target addr", NULL},
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},
794134789Sbrian  {NULL, NULL, NULL, 0, NULL, NULL, NULL},
79540561Sbrian};
79640561Sbrian#endif
79740561Sbrian
79840561Sbrianstatic struct cmdtab const AllowCommands[] = {
79940561Sbrian  {"modes", "mode", AllowModes, LOCAL_AUTH,
800134789Sbrian  "Only allow certain ppp modes", "allow modes mode...", NULL},
80140561Sbrian  {"users", "user", AllowUsers, LOCAL_AUTH,
802134789Sbrian  "Only allow ppp access to certain users", "allow users logname...", NULL},
80340561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
80440561Sbrian  "Display this message", "allow help|? [command]", AllowCommands},
805134789Sbrian  {NULL, NULL, NULL, 0, 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,
816134789Sbrian   "Clear iface address(es)", "iface clear [INET | INET6]", NULL},
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,
824134789Sbrian   "Show iface address(es)", "iface show", NULL},
82540561Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
82650059Sbrian   "Display this message", "nat help|? [command]", IfaceCommands},
827134789Sbrian  {NULL, NULL, NULL, 0, NULL, NULL, NULL},
82840561Sbrian};
82940561Sbrian
83030715Sbrianstatic struct cmdtab const Commands[] = {
83136285Sbrian  {"accept", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
832134789Sbrian  "accept option request", "accept option ..", NULL},
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,
840134789Sbrian  "Run a background command", "[!]bg command", NULL},
84136934Sbrian  {"clear", NULL, ClearCommand, LOCAL_AUTH | LOCAL_CX_OPT,
84246686Sbrian  "Clear throughput statistics",
843134789Sbrian  "clear ipcp|ipv6cp|physical [current|overall|peak]...", NULL},
84436285Sbrian  {"clone", NULL, CloneCommand, LOCAL_AUTH | LOCAL_CX,
845134789Sbrian  "Clone a link", "clone newname...", NULL},
84636285Sbrian  {"close", NULL, CloseCommand, LOCAL_AUTH | LOCAL_CX_OPT,
847134789Sbrian  "Close an FSM", "close [lcp|ccp]", NULL},
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,
853134789Sbrian  "Deny option request", "deny option ..", NULL},
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,
857134789Sbrian  "Disable option", "disable option ..", NULL},
85836285Sbrian  {"down", NULL, DownCommand, LOCAL_AUTH | LOCAL_CX_OPT,
859134789Sbrian  "Generate a down event", "down [ccp|lcp]", NULL},
86036285Sbrian  {"enable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
861134789Sbrian  "Enable option", "enable option ..", NULL},
86263484Sbrian  {"ident", NULL, IdentCommand, LOCAL_AUTH | LOCAL_CX,
863134789Sbrian  "Set the link identity", "ident text...", NULL},
86440561Sbrian  {"iface", "interface", RunListCommand, LOCAL_AUTH,
86540561Sbrian  "interface control", "iface option ...", IfaceCommands},
86636285Sbrian  {"link", "datalink", LinkCommand, LOCAL_AUTH,
867134789Sbrian  "Link specific commands", "link name command ...", NULL},
86837008Sbrian  {"load", NULL, LoadCommand, LOCAL_AUTH | LOCAL_CX_OPT,
869134789Sbrian  "Load settings", "load [system ...]", NULL},
87085991Sbrian  {"log", NULL, LogCommand, LOCAL_AUTH | LOCAL_CX_OPT,
871134789Sbrian  "log information", "log word ...", NULL},
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,
879134789Sbrian  "Password for manipulation", "passwd LocalPassword", NULL},
88036285Sbrian  {"quit", "bye", QuitCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
881134789Sbrian  "Quit PPP program", "quit|bye [all]", NULL},
88236285Sbrian  {"remove", "rm", RemoveCommand, LOCAL_AUTH | LOCAL_CX,
883134789Sbrian  "Remove a link", "remove", NULL},
88436285Sbrian  {"rename", "mv", RenameCommand, LOCAL_AUTH | LOCAL_CX,
885134789Sbrian  "Rename a link", "rename name", NULL},
88658044Sbrian  {"resolv", NULL, ResolvCommand, LOCAL_AUTH,
887134789Sbrian  "Manipulate resolv.conf", "resolv readonly|reload|restore|rewrite|writable",
888134789Sbrian  NULL},
88928679Sbrian  {"save", NULL, SaveCommand, LOCAL_AUTH,
890134789Sbrian  "Save settings", "save", NULL},
89163484Sbrian  {"sendident", NULL, SendIdentification, LOCAL_AUTH | LOCAL_CX,
892134789Sbrian  "Transmit the link identity", "sendident", NULL},
89336285Sbrian  {"set", "setup", SetCommand, LOCAL_AUTH | LOCAL_CX_OPT,
894134789Sbrian  "Set parameters", "set[up] var value", NULL},
89528679Sbrian  {"shell", "!", FgShellCommand, LOCAL_AUTH,
896134789Sbrian  "Run a subshell", "shell|! [sh command]", NULL},
89736285Sbrian  {"show", NULL, ShowCommand, LOCAL_AUTH | LOCAL_CX_OPT,
898134789Sbrian  "Show status and stats", "show var", NULL},
89936285Sbrian  {"term", NULL, TerminalCommand, LOCAL_AUTH | LOCAL_CX,
900134789Sbrian  "Enter terminal mode", "term", NULL},
90128679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
90231343Sbrian  "Display this message", "help|? [command]", Commands},
903134789Sbrian  {NULL, NULL, NULL, 0, NULL, NULL, NULL},
9046059Samurai};
9056059Samurai
90628536Sbrianstatic int
90731343SbrianShowEscape(struct cmdargs const *arg)
9086059Samurai{
90936285Sbrian  if (arg->cx->physical->async.cfg.EscMap[32]) {
91036285Sbrian    int code, bit;
91136285Sbrian    const char *sep = "";
9126059Samurai
91326516Sbrian    for (code = 0; code < 32; code++)
91436285Sbrian      if (arg->cx->physical->async.cfg.EscMap[code])
91528679Sbrian	for (bit = 0; bit < 8; bit++)
91636285Sbrian	  if (arg->cx->physical->async.cfg.EscMap[code] & (1 << bit)) {
91736285Sbrian	    prompt_Printf(arg->prompt, "%s0x%02x", sep, (code << 3) + bit);
91836285Sbrian            sep = ", ";
91936285Sbrian          }
92036285Sbrian    prompt_Printf(arg->prompt, "\n");
9216059Samurai  }
92231077Sbrian  return 0;
9236059Samurai}
9246059Samurai
92528679Sbrianstatic int
92636285SbrianShowTimerList(struct cmdargs const *arg)
9276059Samurai{
92836285Sbrian  timer_Show(0, arg->prompt);
92931077Sbrian  return 0;
9306059Samurai}
9316059Samurai
93228679Sbrianstatic int
93331343SbrianShowStopped(struct cmdargs const *arg)
93428327Sbrian{
93536285Sbrian  prompt_Printf(arg->prompt, " Stopped Timer:  LCP: ");
93636285Sbrian  if (!arg->cx->physical->link.lcp.fsm.StoppedTimer.load)
93736285Sbrian    prompt_Printf(arg->prompt, "Disabled");
93828327Sbrian  else
93936285Sbrian    prompt_Printf(arg->prompt, "%ld secs",
94036285Sbrian                  arg->cx->physical->link.lcp.fsm.StoppedTimer.load / SECTICKS);
94128461Sbrian
94236285Sbrian  prompt_Printf(arg->prompt, ", CCP: ");
94336285Sbrian  if (!arg->cx->physical->link.ccp.fsm.StoppedTimer.load)
94436285Sbrian    prompt_Printf(arg->prompt, "Disabled");
94528461Sbrian  else
94636285Sbrian    prompt_Printf(arg->prompt, "%ld secs",
94736285Sbrian                  arg->cx->physical->link.ccp.fsm.StoppedTimer.load / SECTICKS);
94828461Sbrian
94936285Sbrian  prompt_Printf(arg->prompt, "\n");
95028461Sbrian
95131077Sbrian  return 0;
95228327Sbrian}
95328327Sbrian
95428679Sbrianstatic int
95531343SbrianShowVersion(struct cmdargs const *arg)
9566059Samurai{
95751026Sbrian  prompt_Printf(arg->prompt, "PPP Version %s - %s\n", Version, __DATE__);
95831077Sbrian  return 0;
9596059Samurai}
9606059Samurai
96128679Sbrianstatic int
96236285SbrianShowProtocolStats(struct cmdargs const *arg)
96326326Sbrian{
96436285Sbrian  struct link *l = command_ChooseLink(arg);
96526326Sbrian
96636285Sbrian  prompt_Printf(arg->prompt, "%s:\n", l->name);
96736285Sbrian  link_ReportProtocolStatus(l, arg->prompt);
96831077Sbrian  return 0;
96926326Sbrian}
97026326Sbrian
97130715Sbrianstatic struct cmdtab const ShowCommands[] = {
97236285Sbrian  {"bundle", NULL, bundle_ShowStatus, LOCAL_AUTH,
973134789Sbrian  "bundle details", "show bundle", NULL},
97436285Sbrian  {"ccp", NULL, ccp_ReportStatus, LOCAL_AUTH | LOCAL_CX_OPT,
975134789Sbrian  "CCP status", "show cpp", NULL},
97636285Sbrian  {"compress", NULL, sl_Show, LOCAL_AUTH,
977134789Sbrian  "VJ compression stats", "show compress", NULL},
97836285Sbrian  {"escape", NULL, ShowEscape, LOCAL_AUTH | LOCAL_CX,
979134789Sbrian  "escape characters", "show escape", NULL},
98036285Sbrian  {"filter", NULL, filter_Show, LOCAL_AUTH,
981134789Sbrian  "packet filters", "show filter [in|out|dial|alive]", NULL},
98236285Sbrian  {"hdlc", NULL, hdlc_ReportStatus, LOCAL_AUTH | LOCAL_CX,
983134789Sbrian  "HDLC errors", "show hdlc", NULL},
98440561Sbrian  {"iface", "interface", iface_Show, LOCAL_AUTH,
985134789Sbrian  "Interface status", "show iface", NULL},
98636285Sbrian  {"ipcp", NULL, ipcp_Show, LOCAL_AUTH,
987134789Sbrian  "IPCP status", "show ipcp", NULL},
98881634Sbrian#ifndef NOINET6
98981634Sbrian  {"ipv6cp", NULL, ipv6cp_Show, LOCAL_AUTH,
990134789Sbrian  "IPV6CP status", "show ipv6cp", NULL},
99181634Sbrian#endif
99247211Sbrian  {"layers", NULL, link_ShowLayers, LOCAL_AUTH | LOCAL_CX_OPT,
993134789Sbrian  "Protocol layers", "show layers", NULL},
99436285Sbrian  {"lcp", NULL, lcp_ReportStatus, LOCAL_AUTH | LOCAL_CX,
995134789Sbrian  "LCP status", "show lcp", NULL},
99636285Sbrian  {"link", "datalink", datalink_Show, LOCAL_AUTH | LOCAL_CX,
997134789Sbrian  "(high-level) link info", "show link", NULL},
99836285Sbrian  {"links", NULL, bundle_ShowLinks, LOCAL_AUTH,
999134789Sbrian  "available link names", "show links", NULL},
100036285Sbrian  {"log", NULL, log_ShowLevel, LOCAL_AUTH,
1001134789Sbrian  "log levels", "show log", NULL},
100236285Sbrian  {"mem", NULL, mbuf_Show, LOCAL_AUTH,
1003134789Sbrian  "mbuf allocations", "show mem", NULL},
100481634Sbrian  {"ncp", NULL, ncp_Show, LOCAL_AUTH,
1005134789Sbrian  "NCP status", "show ncp", NULL},
100646686Sbrian  {"physical", NULL, physical_ShowStatus, LOCAL_AUTH | LOCAL_CX,
1007134789Sbrian  "(low-level) link info", "show physical", NULL},
100836285Sbrian  {"mp", "multilink", mp_ShowStatus, LOCAL_AUTH,
1009134789Sbrian  "multilink setup", "show mp", NULL},
101036285Sbrian  {"proto", NULL, ShowProtocolStats, LOCAL_AUTH | LOCAL_CX_OPT,
1011134789Sbrian  "protocol summary", "show proto", NULL},
101236285Sbrian  {"route", NULL, route_Show, LOCAL_AUTH,
1013134789Sbrian  "routing table", "show route", NULL},
101436285Sbrian  {"stopped", NULL, ShowStopped, LOCAL_AUTH | LOCAL_CX,
1015134789Sbrian  "STOPPED timeout", "show stopped", NULL},
101636285Sbrian  {"timers", NULL, ShowTimerList, LOCAL_AUTH,
1017134789Sbrian  "alarm timers", "show timers", NULL},
101828679Sbrian  {"version", NULL, ShowVersion, LOCAL_NO_AUTH | LOCAL_AUTH,
1019134789Sbrian  "version string", "show version", NULL},
102036285Sbrian  {"who", NULL, log_ShowWho, LOCAL_AUTH,
1021134789Sbrian  "client list", "show who", NULL},
102228679Sbrian  {"help", "?", HelpCommand, LOCAL_NO_AUTH | LOCAL_AUTH,
102331343Sbrian  "Display this message", "show help|? [command]", ShowCommands},
1024134789Sbrian  {NULL, NULL, NULL, 0, NULL, NULL, NULL},
10256059Samurai};
10266059Samurai
102730715Sbrianstatic struct cmdtab const *
102831343SbrianFindCommand(struct cmdtab const *cmds, const char *str, int *pmatch)
10296059Samurai{
103026516Sbrian  int nmatch;
103126516Sbrian  int len;
103228679Sbrian  struct cmdtab const *found;
10336059Samurai
103426516Sbrian  found = NULL;
103526516Sbrian  len = strlen(str);
103626516Sbrian  nmatch = 0;
10376059Samurai  while (cmds->func) {
103825566Sbrian    if (cmds->name && strncasecmp(str, cmds->name, len) == 0) {
103926516Sbrian      if (cmds->name[len] == '\0') {
104028679Sbrian	*pmatch = 1;
104128679Sbrian	return cmds;
104226516Sbrian      }
10436059Samurai      nmatch++;
10446059Samurai      found = cmds;
104528679Sbrian    } else if (cmds->alias && strncasecmp(str, cmds->alias, len) == 0) {
104626516Sbrian      if (cmds->alias[len] == '\0') {
104728679Sbrian	*pmatch = 1;
104828679Sbrian	return cmds;
104926516Sbrian      }
10506059Samurai      nmatch++;
10516059Samurai      found = cmds;
10526059Samurai    }
10536059Samurai    cmds++;
10546059Samurai  }
10556059Samurai  *pmatch = nmatch;
105626516Sbrian  return found;
10576059Samurai}
10586059Samurai
105936285Sbrianstatic const char *
106036285SbrianmkPrefix(int argc, char const *const *argv, char *tgt, int sz)
106136285Sbrian{
106236285Sbrian  int f, tlen, len;
106336285Sbrian
106436285Sbrian  tlen = 0;
106536285Sbrian  for (f = 0; f < argc && tlen < sz - 2; f++) {
106636285Sbrian    if (f)
106736285Sbrian      tgt[tlen++] = ' ';
106836285Sbrian    len = strlen(argv[f]);
106936285Sbrian    if (len > sz - tlen - 1)
107036285Sbrian      len = sz - tlen - 1;
107136285Sbrian    strncpy(tgt+tlen, argv[f], len);
107236285Sbrian    tlen += len;
107336285Sbrian  }
107436285Sbrian  tgt[tlen] = '\0';
107536285Sbrian  return tgt;
107636285Sbrian}
107736285Sbrian
107830715Sbrianstatic int
107936285SbrianFindExec(struct bundle *bundle, struct cmdtab const *cmds, int argc, int argn,
108036285Sbrian         char const *const *argv, struct prompt *prompt, struct datalink *cx)
10816059Samurai{
108228679Sbrian  struct cmdtab const *cmd;
10836059Samurai  int val = 1;
10846059Samurai  int nmatch;
108531343Sbrian  struct cmdargs arg;
108636285Sbrian  char prefix[100];
10876059Samurai
108836285Sbrian  cmd = FindCommand(cmds, argv[argn], &nmatch);
10896059Samurai  if (nmatch > 1)
109036285Sbrian    log_Printf(LogWARN, "%s: Ambiguous command\n",
109136285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix));
109236285Sbrian  else if (cmd && (!prompt || (cmd->lauth & prompt->auth))) {
109336285Sbrian    if ((cmd->lauth & LOCAL_CX) && !cx)
109436285Sbrian      /* We've got no context, but we require it */
109536285Sbrian      cx = bundle2datalink(bundle, NULL);
109636285Sbrian
109736285Sbrian    if ((cmd->lauth & LOCAL_CX) && !cx)
109836285Sbrian      log_Printf(LogWARN, "%s: No context (use the `link' command)\n",
109936285Sbrian                mkPrefix(argn+1, argv, prefix, sizeof prefix));
110036285Sbrian    else {
110136285Sbrian      if (cx && !(cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
110236285Sbrian        log_Printf(LogWARN, "%s: Redundant context (%s) ignored\n",
110336285Sbrian                  mkPrefix(argn+1, argv, prefix, sizeof prefix), cx->name);
110436285Sbrian        cx = NULL;
110536285Sbrian      }
110636285Sbrian      arg.cmdtab = cmds;
110736285Sbrian      arg.cmd = cmd;
110836285Sbrian      arg.argc = argc;
110936285Sbrian      arg.argn = argn+1;
111036285Sbrian      arg.argv = argv;
111136285Sbrian      arg.bundle = bundle;
111236285Sbrian      arg.cx = cx;
111336285Sbrian      arg.prompt = prompt;
111436285Sbrian      val = (*cmd->func) (&arg);
111536285Sbrian    }
111631343Sbrian  } else
111736285Sbrian    log_Printf(LogWARN, "%s: Invalid command\n",
111836285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix));
111926516Sbrian
112026516Sbrian  if (val == -1)
112195258Sdes    log_Printf(LogWARN, "usage: %s\n", cmd->syntax);
112228679Sbrian  else if (val)
112336285Sbrian    log_Printf(LogWARN, "%s: Failed %d\n",
112436285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix), val);
112526516Sbrian
112626516Sbrian  return val;
11276059Samurai}
11286059Samurai
112937009Sbrianint
113058045Sbriancommand_Expand_Interpret(char *buff, int nb, char *argv[MAXARGS], int offset)
113158045Sbrian{
113258045Sbrian  char buff2[LINE_LEN-offset];
113358045Sbrian
113458045Sbrian  InterpretArg(buff, buff2);
113558045Sbrian  strncpy(buff, buff2, LINE_LEN - offset - 1);
113658045Sbrian  buff[LINE_LEN - offset - 1] = '\0';
113758045Sbrian
113858045Sbrian  return command_Interpret(buff, nb, argv);
113958045Sbrian}
114058045Sbrian
114158045Sbrianint
114237009Sbriancommand_Interpret(char *buff, int nb, char *argv[MAXARGS])
11436059Samurai{
11446059Samurai  char *cp;
11456059Samurai
11466059Samurai  if (nb > 0) {
11476059Samurai    cp = buff + strcspn(buff, "\r\n");
11486059Samurai    if (cp)
11496059Samurai      *cp = '\0';
115055145Sbrian    return MakeArgs(buff, argv, MAXARGS, PARSE_REDUCE);
115137009Sbrian  }
115237009Sbrian  return 0;
115331121Sbrian}
11546059Samurai
115531822Sbrianstatic int
1156134789Sbrianarghidden(char const *const *argv, int n)
115731822Sbrian{
115831822Sbrian  /* Is arg n of the given command to be hidden from the log ? */
115931828Sbrian
116031828Sbrian  /* set authkey xxxxx */
116131828Sbrian  /* set key xxxxx */
116231822Sbrian  if (n == 2 && !strncasecmp(argv[0], "se", 2) &&
116331822Sbrian      (!strncasecmp(argv[1], "authk", 5) || !strncasecmp(argv[1], "ke", 2)))
116431822Sbrian    return 1;
116531822Sbrian
116631828Sbrian  /* passwd xxxxx */
116731828Sbrian  if (n == 1 && !strncasecmp(argv[0], "p", 1))
116831828Sbrian    return 1;
116931828Sbrian
117036285Sbrian  /* set server port xxxxx .... */
117136285Sbrian  if (n == 3 && !strncasecmp(argv[0], "se", 2) &&
117236285Sbrian      !strncasecmp(argv[1], "se", 2))
117336285Sbrian    return 1;
117436285Sbrian
117531822Sbrian  return 0;
117631822Sbrian}
117731822Sbrian
117831121Sbrianvoid
117936285Sbriancommand_Run(struct bundle *bundle, int argc, char const *const *argv,
118037008Sbrian           struct prompt *prompt, const char *label, struct datalink *cx)
118131121Sbrian{
118231156Sbrian  if (argc > 0) {
118336285Sbrian    if (log_IsKept(LogCOMMAND)) {
118447844Sbrian      char buf[LINE_LEN];
1185134789Sbrian      int f;
1186134789Sbrian      size_t n;
118731156Sbrian
118831156Sbrian      if (label) {
118931962Sbrian        strncpy(buf, label, sizeof buf - 3);
119031962Sbrian        buf[sizeof buf - 3] = '\0';
119131156Sbrian        strcat(buf, ": ");
119247844Sbrian        n = strlen(buf);
119347844Sbrian      } else {
119447844Sbrian        *buf = '\0';
119547844Sbrian        n = 0;
119631156Sbrian      }
119747844Sbrian      buf[sizeof buf - 1] = '\0';	/* In case we run out of room in buf */
119847844Sbrian
119931156Sbrian      for (f = 0; f < argc; f++) {
120031962Sbrian        if (n < sizeof buf - 1 && f)
120131156Sbrian          buf[n++] = ' ';
1202134789Sbrian        if (arghidden(argv, f))
120336285Sbrian          strncpy(buf+n, "********", sizeof buf - n - 1);
120431822Sbrian        else
120531962Sbrian          strncpy(buf+n, argv[f], sizeof buf - n - 1);
120631156Sbrian        n += strlen(buf+n);
120731156Sbrian      }
120836285Sbrian      log_Printf(LogCOMMAND, "%s\n", buf);
120931156Sbrian    }
121037008Sbrian    FindExec(bundle, Commands, argc, 0, argv, prompt, cx);
121131156Sbrian  }
12126059Samurai}
12136059Samurai
121454914Sbrianint
121536285Sbriancommand_Decode(struct bundle *bundle, char *buff, int nb, struct prompt *prompt,
121636285Sbrian              const char *label)
121731121Sbrian{
121831121Sbrian  int argc;
121937009Sbrian  char *argv[MAXARGS];
122031121Sbrian
122158045Sbrian  if ((argc = command_Expand_Interpret(buff, nb, argv, 0)) < 0)
122254914Sbrian    return 0;
122354914Sbrian
122437008Sbrian  command_Run(bundle, argc, (char const *const *)argv, prompt, label, NULL);
122554914Sbrian  return 1;
122631121Sbrian}
122731121Sbrian
12286059Samuraistatic int
122931343SbrianShowCommand(struct cmdargs const *arg)
12306059Samurai{
123136285Sbrian  if (!arg->prompt)
123236285Sbrian    log_Printf(LogWARN, "show: Cannot show without a prompt\n");
123336285Sbrian  else if (arg->argc > arg->argn)
123436285Sbrian    FindExec(arg->bundle, ShowCommands, arg->argc, arg->argn, arg->argv,
123536285Sbrian             arg->prompt, arg->cx);
12366059Samurai  else
123736285Sbrian    prompt_Printf(arg->prompt, "Use ``show ?'' to get a list.\n");
123826516Sbrian
123926516Sbrian  return 0;
12406059Samurai}
12416059Samurai
12426059Samuraistatic int
124331343SbrianTerminalCommand(struct cmdargs const *arg)
12446059Samurai{
124536285Sbrian  if (!arg->prompt) {
124636285Sbrian    log_Printf(LogWARN, "term: Need a prompt\n");
124726516Sbrian    return 1;
12486059Samurai  }
124936285Sbrian
125036285Sbrian  if (arg->cx->physical->link.lcp.fsm.state > ST_CLOSED) {
125136285Sbrian    prompt_Printf(arg->prompt, "LCP state is [%s]\n",
125236285Sbrian                  State2Nam(arg->cx->physical->link.lcp.fsm.state));
125336285Sbrian    return 1;
12546059Samurai  }
125536285Sbrian
125636285Sbrian  datalink_Up(arg->cx, 0, 0);
125736285Sbrian  prompt_TtyTermMode(arg->prompt, arg->cx);
125836285Sbrian  return 0;
12596059Samurai}
12606059Samurai
12616059Samuraistatic int
126231343SbrianQuitCommand(struct cmdargs const *arg)
12636059Samurai{
126436285Sbrian  if (!arg->prompt || prompt_IsController(arg->prompt) ||
126536285Sbrian      (arg->argc > arg->argn && !strcasecmp(arg->argv[arg->argn], "all") &&
126636285Sbrian       (arg->prompt->auth & LOCAL_AUTH)))
1267134789Sbrian    Cleanup();
126836285Sbrian  if (arg->prompt)
126936285Sbrian    prompt_Destroy(arg->prompt, 1);
127026516Sbrian
127126516Sbrian  return 0;
12726059Samurai}
12736059Samurai
12746059Samuraistatic int
127536285SbrianOpenCommand(struct cmdargs const *arg)
12766059Samurai{
127737160Sbrian  if (arg->argc == arg->argn)
127837993Sbrian    bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1);
127937160Sbrian  else if (arg->argc == arg->argn + 1) {
128037160Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp")) {
128137385Sbrian      struct datalink *cx = arg->cx ?
128237385Sbrian        arg->cx : bundle2datalink(arg->bundle, NULL);
128337385Sbrian      if (cx) {
128437385Sbrian        if (cx->physical->link.lcp.fsm.state == ST_OPENED)
128537385Sbrian          fsm_Reopen(&cx->physical->link.lcp.fsm);
128637160Sbrian        else
128737993Sbrian          bundle_Open(arg->bundle, cx->name, PHYS_ALL, 1);
128837160Sbrian      } else
128937160Sbrian        log_Printf(LogWARN, "open lcp: You must specify a link\n");
129037160Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) {
129137160Sbrian      struct fsm *fp;
12926059Samurai
129337210Sbrian      fp = &command_ChooseLink(arg)->ccp.fsm;
129437160Sbrian      if (fp->link->lcp.fsm.state != ST_OPENED)
129537160Sbrian        log_Printf(LogWARN, "open: LCP must be open before opening CCP\n");
129637160Sbrian      else if (fp->state == ST_OPENED)
129737160Sbrian        fsm_Reopen(fp);
129837160Sbrian      else {
129937160Sbrian        fp->open_mode = 0;	/* Not passive any more */
130037160Sbrian        if (fp->state == ST_STOPPED) {
130137160Sbrian          fsm_Down(fp);
130237160Sbrian          fsm_Up(fp);
130337160Sbrian        } else {
130437160Sbrian          fsm_Up(fp);
130537160Sbrian          fsm_Open(fp);
130637160Sbrian        }
130736285Sbrian      }
130837160Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ipcp")) {
130937160Sbrian      if (arg->cx)
131037160Sbrian        log_Printf(LogWARN, "open ipcp: You need not specify a link\n");
131137160Sbrian      if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED)
131237160Sbrian        fsm_Reopen(&arg->bundle->ncp.ipcp.fsm);
131337160Sbrian      else
131437993Sbrian        bundle_Open(arg->bundle, NULL, PHYS_ALL, 1);
131537160Sbrian    } else
131637160Sbrian      return -1;
131736285Sbrian  } else
131836285Sbrian    return -1;
131936285Sbrian
132026516Sbrian  return 0;
13216059Samurai}
13226059Samurai
132325067Sbrianstatic int
132436285SbrianCloseCommand(struct cmdargs const *arg)
13256059Samurai{
132637007Sbrian  if (arg->argc == arg->argn)
132737007Sbrian    bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_STAYDOWN);
132837007Sbrian  else if (arg->argc == arg->argn + 1) {
132937007Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp"))
133037007Sbrian      bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_LCP);
133137007Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "ccp") ||
133237007Sbrian             !strcasecmp(arg->argv[arg->argn], "ccp!")) {
133337007Sbrian      struct fsm *fp;
13346059Samurai
133537210Sbrian      fp = &command_ChooseLink(arg)->ccp.fsm;
133637007Sbrian      if (fp->state == ST_OPENED) {
133737007Sbrian        fsm_Close(fp);
133837007Sbrian        if (arg->argv[arg->argn][3] == '!')
133937007Sbrian          fp->open_mode = 0;		/* Stay ST_CLOSED */
134037007Sbrian        else
134137007Sbrian          fp->open_mode = OPEN_PASSIVE;	/* Wait for the peer to start */
134237007Sbrian      }
134337007Sbrian    } else
134436285Sbrian      return -1;
134536285Sbrian  } else
134636285Sbrian    return -1;
134736285Sbrian
134836285Sbrian  return 0;
13496059Samurai}
13506059Samurai
135125067Sbrianstatic int
135236285SbrianDownCommand(struct cmdargs const *arg)
135311336Samurai{
135437018Sbrian  if (arg->argc == arg->argn) {
135537018Sbrian      if (arg->cx)
135637018Sbrian        datalink_Down(arg->cx, CLOSE_STAYDOWN);
135737018Sbrian      else
135837018Sbrian        bundle_Down(arg->bundle, CLOSE_STAYDOWN);
135937018Sbrian  } else if (arg->argc == arg->argn + 1) {
136037018Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp")) {
136137018Sbrian      if (arg->cx)
136237018Sbrian        datalink_Down(arg->cx, CLOSE_LCP);
136337018Sbrian      else
136437018Sbrian        bundle_Down(arg->bundle, CLOSE_LCP);
136537018Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) {
136637018Sbrian      struct fsm *fp = arg->cx ? &arg->cx->physical->link.ccp.fsm :
136737018Sbrian                                 &arg->bundle->ncp.mp.link.ccp.fsm;
136837060Sbrian      fsm2initial(fp);
136937018Sbrian    } else
137037018Sbrian      return -1;
137136285Sbrian  } else
137236285Sbrian    return -1;
137336285Sbrian
137436285Sbrian  return 0;
137525067Sbrian}
137625067Sbrian
137725067Sbrianstatic int
137836285SbrianSetModemSpeed(struct cmdargs const *arg)
137925067Sbrian{
138036285Sbrian  long speed;
138136285Sbrian  char *end;
138211336Samurai
138336285Sbrian  if (arg->argc > arg->argn && *arg->argv[arg->argn]) {
138436285Sbrian    if (arg->argc > arg->argn+1) {
138554917Sbrian      log_Printf(LogWARN, "SetModemSpeed: Too many arguments\n");
138636285Sbrian      return -1;
138711336Samurai    }
138836285Sbrian    if (strcasecmp(arg->argv[arg->argn], "sync") == 0) {
138936285Sbrian      physical_SetSync(arg->cx->physical);
139036285Sbrian      return 0;
139136285Sbrian    }
139236285Sbrian    end = NULL;
139336285Sbrian    speed = strtol(arg->argv[arg->argn], &end, 10);
1394134789Sbrian    if (*end || speed < 0) {
139536285Sbrian      log_Printf(LogWARN, "SetModemSpeed: Bad argument \"%s\"",
139636285Sbrian                arg->argv[arg->argn]);
139736285Sbrian      return -1;
139836285Sbrian    }
139936285Sbrian    if (physical_SetSpeed(arg->cx->physical, speed))
140036285Sbrian      return 0;
140136285Sbrian    log_Printf(LogWARN, "%s: Invalid speed\n", arg->argv[arg->argn]);
140236285Sbrian  } else
140336285Sbrian    log_Printf(LogWARN, "SetModemSpeed: No speed specified\n");
140424939Sbrian
140526516Sbrian  return -1;
140611336Samurai}
140711336Samurai
140825067Sbrianstatic int
140931343SbrianSetStoppedTimeout(struct cmdargs const *arg)
141028327Sbrian{
141136285Sbrian  struct link *l = &arg->cx->physical->link;
141236285Sbrian
141336285Sbrian  l->lcp.fsm.StoppedTimer.load = 0;
141436285Sbrian  l->ccp.fsm.StoppedTimer.load = 0;
141536285Sbrian  if (arg->argc <= arg->argn+2) {
141636285Sbrian    if (arg->argc > arg->argn) {
141736285Sbrian      l->lcp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn]) * SECTICKS;
141836285Sbrian      if (arg->argc > arg->argn+1)
141936285Sbrian        l->ccp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn+1]) * SECTICKS;
142028461Sbrian    }
142128327Sbrian    return 0;
142228327Sbrian  }
142328327Sbrian  return -1;
142428327Sbrian}
142528327Sbrian
142628327Sbrianstatic int
142731343SbrianSetServer(struct cmdargs const *arg)
142826940Sbrian{
142926940Sbrian  int res = -1;
143026940Sbrian
143136285Sbrian  if (arg->argc > arg->argn && arg->argc < arg->argn+4) {
143231081Sbrian    const char *port, *passwd, *mask;
1433134789Sbrian    size_t mlen;
143431081Sbrian
143531081Sbrian    /* What's what ? */
143636285Sbrian    port = arg->argv[arg->argn];
143736285Sbrian    if (arg->argc == arg->argn + 2) {
143836285Sbrian      passwd = arg->argv[arg->argn+1];
143936285Sbrian      mask = NULL;
144036285Sbrian    } else if (arg->argc == arg->argn + 3) {
144136285Sbrian      passwd = arg->argv[arg->argn+1];
144236285Sbrian      mask = arg->argv[arg->argn+2];
144353125Sbrian      mlen = strlen(mask);
144453125Sbrian      if (mlen == 0 || mlen > 4 || strspn(mask, "01234567") != mlen ||
144553125Sbrian          (mlen == 4 && *mask != '0')) {
144653125Sbrian        log_Printf(LogWARN, "%s %s: %s: Invalid mask\n",
144753125Sbrian                   arg->argv[arg->argn - 2], arg->argv[arg->argn - 1], mask);
144831081Sbrian        return -1;
144953125Sbrian      }
145071764Sbrian    } else if (arg->argc != arg->argn + 1)
145171764Sbrian      return -1;
145271764Sbrian    else if (strcasecmp(port, "none") == 0) {
145371657Sbrian      if (server_Clear(arg->bundle))
145471657Sbrian        log_Printf(LogPHASE, "Disabled server socket\n");
145571657Sbrian      return 0;
145671657Sbrian    } else if (strcasecmp(port, "open") == 0) {
145771657Sbrian      switch (server_Reopen(arg->bundle)) {
145871657Sbrian        case SERVER_OK:
145971657Sbrian          return 0;
146071657Sbrian        case SERVER_FAILED:
146171764Sbrian          log_Printf(LogWARN, "Failed to reopen server port\n");
146271657Sbrian          return 1;
146371657Sbrian        case SERVER_UNSET:
146471764Sbrian          log_Printf(LogWARN, "Cannot reopen unset server socket\n");
146571657Sbrian          return 1;
146671657Sbrian        default:
146771657Sbrian          break;
146871657Sbrian      }
146971657Sbrian      return -1;
147071657Sbrian    } else if (strcasecmp(port, "closed") == 0) {
147136285Sbrian      if (server_Close(arg->bundle))
147271657Sbrian        log_Printf(LogPHASE, "Closed server socket\n");
147371657Sbrian      else
147471657Sbrian        log_Printf(LogWARN, "Server socket not open\n");
147571657Sbrian
147636285Sbrian      return 0;
147731081Sbrian    } else
147836285Sbrian      return -1;
147931081Sbrian
148071657Sbrian    strncpy(server.cfg.passwd, passwd, sizeof server.cfg.passwd - 1);
148171657Sbrian    server.cfg.passwd[sizeof server.cfg.passwd - 1] = '\0';
148231081Sbrian
148336285Sbrian    if (*port == '/') {
148431081Sbrian      mode_t imask;
148536285Sbrian      char *ptr, name[LINE_LEN + 12];
148628679Sbrian
148753125Sbrian      if (mask == NULL)
148831081Sbrian        imask = (mode_t)-1;
148953125Sbrian      else for (imask = mlen = 0; mask[mlen]; mlen++)
149053125Sbrian        imask = (imask * 8) + mask[mlen] - '0';
149136285Sbrian
149236285Sbrian      ptr = strstr(port, "%d");
149336285Sbrian      if (ptr) {
149436285Sbrian        snprintf(name, sizeof name, "%.*s%d%s",
149537210Sbrian                 (int)(ptr - port), port, arg->bundle->unit, ptr + 2);
149636285Sbrian        port = name;
149736285Sbrian      }
149836285Sbrian      res = server_LocalOpen(arg->bundle, port, imask);
149927346Sbrian    } else {
150036285Sbrian      int iport, add = 0;
150128679Sbrian
150231081Sbrian      if (mask != NULL)
150331081Sbrian        return -1;
150428679Sbrian
150536285Sbrian      if (*port == '+') {
150636285Sbrian        port++;
150736285Sbrian        add = 1;
150836285Sbrian      }
150931081Sbrian      if (strspn(port, "0123456789") != strlen(port)) {
151031081Sbrian        struct servent *s;
151131081Sbrian
151231081Sbrian        if ((s = getservbyname(port, "tcp")) == NULL) {
151331081Sbrian	  iport = 0;
151436285Sbrian	  log_Printf(LogWARN, "%s: Invalid port or service\n", port);
151528679Sbrian	} else
151631081Sbrian	  iport = ntohs(s->s_port);
151727346Sbrian      } else
151831081Sbrian        iport = atoi(port);
151936285Sbrian
152036285Sbrian      if (iport) {
152136285Sbrian        if (add)
152236285Sbrian          iport += arg->bundle->unit;
152336285Sbrian        res = server_TcpOpen(arg->bundle, iport);
152436285Sbrian      } else
152536285Sbrian        res = -1;
152627346Sbrian    }
152731081Sbrian  }
152826940Sbrian
152926940Sbrian  return res;
153026940Sbrian}
153126940Sbrian
153226940Sbrianstatic int
153331343SbrianSetEscape(struct cmdargs const *arg)
15346059Samurai{
15356059Samurai  int code;
153636285Sbrian  int argc = arg->argc - arg->argn;
153736285Sbrian  char const *const *argv = arg->argv + arg->argn;
15386059Samurai
15396059Samurai  for (code = 0; code < 33; code++)
154036285Sbrian    arg->cx->physical->async.cfg.EscMap[code] = 0;
154131343Sbrian
15426059Samurai  while (argc-- > 0) {
15436059Samurai    sscanf(*argv++, "%x", &code);
15446059Samurai    code &= 0xff;
154536285Sbrian    arg->cx->physical->async.cfg.EscMap[code >> 3] |= (1 << (code & 7));
154636285Sbrian    arg->cx->physical->async.cfg.EscMap[32] = 1;
15476059Samurai  }
154826516Sbrian  return 0;
15496059Samurai}
15506059Samurai
15516059Samuraistatic int
155231343SbrianSetInterfaceAddr(struct cmdargs const *arg)
15536059Samurai{
155481634Sbrian  struct ncp *ncp = &arg->bundle->ncp;
155581634Sbrian  struct ncpaddr ncpaddr;
155632267Sbrian  const char *hisaddr;
155732267Sbrian
155840561Sbrian  if (arg->argc > arg->argn + 4)
155940561Sbrian    return -1;
156040561Sbrian
156132267Sbrian  hisaddr = NULL;
156281634Sbrian  memset(&ncp->ipcp.cfg.my_range, '\0', sizeof ncp->ipcp.cfg.my_range);
156381634Sbrian  memset(&ncp->ipcp.cfg.peer_range, '\0', sizeof ncp->ipcp.cfg.peer_range);
156481634Sbrian  ncp->ipcp.cfg.HaveTriggerAddress = 0;
156581634Sbrian  ncp->ipcp.cfg.netmask.s_addr = INADDR_ANY;
156681634Sbrian  iplist_reset(&ncp->ipcp.cfg.peer_list);
156728394Sbrian
156836285Sbrian  if (arg->argc > arg->argn) {
156981634Sbrian    if (!ncprange_aton(&ncp->ipcp.cfg.my_range, ncp, arg->argv[arg->argn]))
157028679Sbrian      return 1;
157136285Sbrian    if (arg->argc > arg->argn+1) {
157236285Sbrian      hisaddr = arg->argv[arg->argn+1];
157336285Sbrian      if (arg->argc > arg->argn+2) {
157481634Sbrian        ncp->ipcp.ifmask = ncp->ipcp.cfg.netmask =
157581634Sbrian          GetIpAddr(arg->argv[arg->argn+2]);
157636285Sbrian	if (arg->argc > arg->argn+3) {
157781634Sbrian	  ncp->ipcp.cfg.TriggerAddress = GetIpAddr(arg->argv[arg->argn+3]);
157881634Sbrian	  ncp->ipcp.cfg.HaveTriggerAddress = 1;
15799440Samurai	}
15806059Samurai      }
15816059Samurai    }
15826059Samurai  }
158328394Sbrian
158440561Sbrian  /* 0.0.0.0 means any address (0 bits) */
1585132204Sbrian  ncprange_getaddr(&ncp->ipcp.cfg.my_range, &ncpaddr);
158681634Sbrian  ncpaddr_getip4(&ncpaddr, &ncp->ipcp.my_ip);
158781634Sbrian  if (ncp->ipcp.my_ip.s_addr == INADDR_ANY)
158881634Sbrian    ncprange_setwidth(&ncp->ipcp.cfg.my_range, 0);
158981634Sbrian  bundle_AdjustFilters(arg->bundle, &ncpaddr, NULL);
159036285Sbrian
159136285Sbrian  if (hisaddr && !ipcp_UseHisaddr(arg->bundle, hisaddr,
159236928Sbrian                                  arg->bundle->phys_type.all & PHYS_AUTO))
159332267Sbrian    return 4;
159431121Sbrian
159526516Sbrian  return 0;
15966059Samurai}
15976059Samurai
159818752Sjkhstatic int
159944305SbrianSetRetry(int argc, char const *const *argv, u_int *timeout, u_int *maxreq,
160044305Sbrian          u_int *maxtrm, int def)
160144305Sbrian{
160244305Sbrian  if (argc == 0) {
160344305Sbrian    *timeout = DEF_FSMRETRY;
160444305Sbrian    *maxreq = def;
160544305Sbrian    if (maxtrm != NULL)
160644305Sbrian      *maxtrm = def;
160744305Sbrian  } else {
160844305Sbrian    long l = atol(argv[0]);
160944305Sbrian
161044305Sbrian    if (l < MIN_FSMRETRY) {
161144305Sbrian      log_Printf(LogWARN, "%ld: Invalid FSM retry period - min %d\n",
161244305Sbrian                 l, MIN_FSMRETRY);
161344305Sbrian      return 1;
161444305Sbrian    } else
161544305Sbrian      *timeout = l;
161644305Sbrian
161744305Sbrian    if (argc > 1) {
161844305Sbrian      l = atol(argv[1]);
161944305Sbrian      if (l < 1) {
162044305Sbrian        log_Printf(LogWARN, "%ld: Invalid FSM REQ tries - changed to 1\n", l);
162144305Sbrian        l = 1;
162244305Sbrian      }
162344305Sbrian      *maxreq = l;
162444305Sbrian
162544305Sbrian      if (argc > 2 && maxtrm != NULL) {
162644305Sbrian        l = atol(argv[2]);
162744305Sbrian        if (l < 1) {
162844305Sbrian          log_Printf(LogWARN, "%ld: Invalid FSM TRM tries - changed to 1\n", l);
162944305Sbrian          l = 1;
163044305Sbrian        }
163144305Sbrian        *maxtrm = l;
163244305Sbrian      }
163344305Sbrian    }
163444305Sbrian  }
163544305Sbrian
163644305Sbrian  return 0;
163744305Sbrian}
163844305Sbrian
163944305Sbrianstatic int
164031343SbrianSetVariable(struct cmdargs const *arg)
16416059Samurai{
164237210Sbrian  long long_val, param = (long)arg->cmd->args;
164379119Sbrian  int mode, dummyint, f, first, res;
164478410Sbrian  u_short *change;
164531343Sbrian  const char *argp;
164636285Sbrian  struct datalink *cx = arg->cx;	/* LOCAL_CX uses this */
164736285Sbrian  struct link *l = command_ChooseLink(arg);	/* LOCAL_CX_OPT uses this */
164881634Sbrian  struct in_addr *ipaddr;
164981634Sbrian  struct ncpaddr ncpaddr[2];
16506059Samurai
165136285Sbrian  if (arg->argc > arg->argn)
165236285Sbrian    argp = arg->argv[arg->argn];
165326551Sbrian  else
165431343Sbrian    argp = "";
165526551Sbrian
165679119Sbrian  res = 0;
165779119Sbrian
165836285Sbrian  if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
165936285Sbrian    log_Printf(LogWARN, "set %s: No context (use the `link' command)\n",
166036285Sbrian              arg->cmd->name);
166136285Sbrian    return 1;
166236285Sbrian  } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
166336285Sbrian    log_Printf(LogWARN, "set %s: Redundant context (%s) ignored\n",
166436285Sbrian              arg->cmd->name, cx->name);
166536285Sbrian    cx = NULL;
166636285Sbrian  }
166736285Sbrian
166826551Sbrian  switch (param) {
166928679Sbrian  case VAR_AUTHKEY:
167050139Sbrian    strncpy(arg->bundle->cfg.auth.key, argp,
167150139Sbrian            sizeof arg->bundle->cfg.auth.key - 1);
167250139Sbrian    arg->bundle->cfg.auth.key[sizeof arg->bundle->cfg.auth.key - 1] = '\0';
167328679Sbrian    break;
167437210Sbrian
167528679Sbrian  case VAR_AUTHNAME:
167640622Sbrian    switch (bundle_Phase(arg->bundle)) {
167758880Sbrian      default:
167858880Sbrian        log_Printf(LogWARN, "Altering authname while at phase %s\n",
167958880Sbrian                   bundle_PhaseName(arg->bundle));
168058880Sbrian        /* drop through */
168140622Sbrian      case PHASE_DEAD:
168240622Sbrian      case PHASE_ESTABLISH:
168340622Sbrian        strncpy(arg->bundle->cfg.auth.name, argp,
168440622Sbrian                sizeof arg->bundle->cfg.auth.name - 1);
168540622Sbrian        arg->bundle->cfg.auth.name[sizeof arg->bundle->cfg.auth.name-1] = '\0';
168640622Sbrian        break;
168736285Sbrian    }
168828679Sbrian    break;
168937210Sbrian
169036285Sbrian  case VAR_AUTOLOAD:
169149434Sbrian    if (arg->argc == arg->argn + 3) {
169298243Sbrian      int v1, v2, v3;
169349434Sbrian      char *end;
169449434Sbrian
169549434Sbrian      v1 = strtol(arg->argv[arg->argn], &end, 0);
169649434Sbrian      if (v1 < 0 || *end) {
169749434Sbrian        log_Printf(LogWARN, "autoload: %s: Invalid min percentage\n",
169849434Sbrian                   arg->argv[arg->argn]);
169979119Sbrian        res = 1;
170079119Sbrian        break;
170136285Sbrian      }
170249434Sbrian
170349434Sbrian      v2 = strtol(arg->argv[arg->argn + 1], &end, 0);
170449434Sbrian      if (v2 < 0 || *end) {
170549434Sbrian        log_Printf(LogWARN, "autoload: %s: Invalid max percentage\n",
170649434Sbrian                   arg->argv[arg->argn + 1]);
170779119Sbrian        res = 1;
170879119Sbrian        break;
170949434Sbrian      }
171049434Sbrian      if (v2 < v1) {
171149434Sbrian        v3 = v1;
171249434Sbrian        v1 = v2;
171349434Sbrian        v2 = v3;
171449434Sbrian      }
171549434Sbrian
171649434Sbrian      v3 = strtol(arg->argv[arg->argn + 2], &end, 0);
171749434Sbrian      if (v3 <= 0 || *end) {
171849434Sbrian        log_Printf(LogWARN, "autoload: %s: Invalid throughput period\n",
171949434Sbrian                   arg->argv[arg->argn + 2]);
172079119Sbrian        res = 1;
172179119Sbrian        break;
172249434Sbrian      }
172349434Sbrian
172449434Sbrian      arg->bundle->ncp.mp.cfg.autoload.min = v1;
172549434Sbrian      arg->bundle->ncp.mp.cfg.autoload.max = v2;
172649434Sbrian      arg->bundle->ncp.mp.cfg.autoload.period = v3;
172749434Sbrian      mp_RestartAutoloadTimer(&arg->bundle->ncp.mp);
172836285Sbrian    } else {
172979119Sbrian      log_Printf(LogWARN, "Set autoload requires three arguments\n");
173079119Sbrian      res = 1;
173136285Sbrian    }
173236285Sbrian    break;
173337210Sbrian
173428679Sbrian  case VAR_DIAL:
173536285Sbrian    strncpy(cx->cfg.script.dial, argp, sizeof cx->cfg.script.dial - 1);
173636285Sbrian    cx->cfg.script.dial[sizeof cx->cfg.script.dial - 1] = '\0';
173728679Sbrian    break;
173837210Sbrian
173928679Sbrian  case VAR_LOGIN:
174036285Sbrian    strncpy(cx->cfg.script.login, argp, sizeof cx->cfg.script.login - 1);
174136285Sbrian    cx->cfg.script.login[sizeof cx->cfg.script.login - 1] = '\0';
174228679Sbrian    break;
174337210Sbrian
174436285Sbrian  case VAR_WINSIZE:
174536285Sbrian    if (arg->argc > arg->argn) {
174636285Sbrian      l->ccp.cfg.deflate.out.winsize = atoi(arg->argv[arg->argn]);
174736285Sbrian      if (l->ccp.cfg.deflate.out.winsize < 8 ||
174836285Sbrian          l->ccp.cfg.deflate.out.winsize > 15) {
174936285Sbrian          log_Printf(LogWARN, "%d: Invalid outgoing window size\n",
175036285Sbrian                    l->ccp.cfg.deflate.out.winsize);
175136285Sbrian          l->ccp.cfg.deflate.out.winsize = 15;
175236285Sbrian      }
175336285Sbrian      if (arg->argc > arg->argn+1) {
175436285Sbrian        l->ccp.cfg.deflate.in.winsize = atoi(arg->argv[arg->argn+1]);
175536285Sbrian        if (l->ccp.cfg.deflate.in.winsize < 8 ||
175636285Sbrian            l->ccp.cfg.deflate.in.winsize > 15) {
175736285Sbrian            log_Printf(LogWARN, "%d: Invalid incoming window size\n",
175836285Sbrian                      l->ccp.cfg.deflate.in.winsize);
175936285Sbrian            l->ccp.cfg.deflate.in.winsize = 15;
176036285Sbrian        }
176136285Sbrian      } else
176236285Sbrian        l->ccp.cfg.deflate.in.winsize = 0;
176336285Sbrian    } else {
176479119Sbrian      log_Printf(LogWARN, "No window size specified\n");
176579119Sbrian      res = 1;
176636285Sbrian    }
176736285Sbrian    break;
176837210Sbrian
176993418Sbrian#ifndef NODES
177078411Sbrian  case VAR_MPPE:
177179119Sbrian    if (arg->argc > arg->argn + 2) {
177279119Sbrian      res = -1;
177379119Sbrian      break;
177479119Sbrian    }
177578411Sbrian
177678411Sbrian    if (arg->argc == arg->argn) {
177778411Sbrian      l->ccp.cfg.mppe.keybits = 0;
177878411Sbrian      l->ccp.cfg.mppe.state = MPPE_ANYSTATE;
177978411Sbrian      l->ccp.cfg.mppe.required = 0;
178078411Sbrian      break;
178178411Sbrian    }
178278411Sbrian
178378411Sbrian    if (!strcmp(argp, "*"))
178478411Sbrian      long_val = 0;
178578411Sbrian    else {
178678411Sbrian      long_val = atol(argp);
178778411Sbrian      if (long_val != 40 && long_val != 56 && long_val != 128) {
178878411Sbrian        log_Printf(LogWARN, "%s: Invalid bits value\n", argp);
178979119Sbrian        res = -1;
179079119Sbrian        break;
179167910Sbrian      }
179267910Sbrian    }
179378411Sbrian
179478411Sbrian    if (arg->argc == arg->argn + 2) {
179578411Sbrian      if (!strcmp(arg->argv[arg->argn + 1], "*"))
179678411Sbrian        l->ccp.cfg.mppe.state = MPPE_ANYSTATE;
179778411Sbrian      else if (!strcasecmp(arg->argv[arg->argn + 1], "stateless"))
179878411Sbrian        l->ccp.cfg.mppe.state = MPPE_STATELESS;
179979370Sbrian      else if (!strcasecmp(arg->argv[arg->argn + 1], "stateful"))
180078411Sbrian        l->ccp.cfg.mppe.state = MPPE_STATEFUL;
180178411Sbrian      else {
180278411Sbrian        log_Printf(LogWARN, "%s: Invalid state value\n",
180378411Sbrian                   arg->argv[arg->argn + 1]);
180479119Sbrian        res = -1;
180579119Sbrian        break;
180678411Sbrian      }
180778411Sbrian    } else
180878411Sbrian      l->ccp.cfg.mppe.state = MPPE_ANYSTATE;
180978411Sbrian    l->ccp.cfg.mppe.keybits = long_val;
181078411Sbrian    l->ccp.cfg.mppe.required = 1;
181167910Sbrian    break;
181267910Sbrian#endif
181367910Sbrian
181428679Sbrian  case VAR_DEVICE:
181536285Sbrian    physical_SetDeviceList(cx->physical, arg->argc - arg->argn,
181636285Sbrian                           arg->argv + arg->argn);
181736285Sbrian    break;
181837210Sbrian
181936285Sbrian  case VAR_ACCMAP:
182036285Sbrian    if (arg->argc > arg->argn) {
182137210Sbrian      u_long ulong_val;
182236285Sbrian      sscanf(argp, "%lx", &ulong_val);
182337210Sbrian      cx->physical->link.lcp.cfg.accmap = (u_int32_t)ulong_val;
182436285Sbrian    } else {
182579119Sbrian      log_Printf(LogWARN, "No accmap specified\n");
182679119Sbrian      res = 1;
182736285Sbrian    }
182836285Sbrian    break;
182937210Sbrian
183036285Sbrian  case VAR_MODE:
183136285Sbrian    mode = Nam2mode(argp);
183236285Sbrian    if (mode == PHYS_NONE || mode == PHYS_ALL) {
183336285Sbrian      log_Printf(LogWARN, "%s: Invalid mode\n", argp);
183479119Sbrian      res = -1;
183579119Sbrian      break;
183636285Sbrian    }
183736285Sbrian    bundle_SetMode(arg->bundle, cx, mode);
183836285Sbrian    break;
183937210Sbrian
184036285Sbrian  case VAR_MRRU:
184140622Sbrian    switch (bundle_Phase(arg->bundle)) {
184240622Sbrian      case PHASE_DEAD:
184340622Sbrian        break;
184440622Sbrian      case PHASE_ESTABLISH:
184540622Sbrian        /* Make sure none of our links are DATALINK_LCP or greater */
184640622Sbrian        if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) {
184740622Sbrian          log_Printf(LogWARN, "mrru: Only changable before LCP negotiations\n");
184879119Sbrian          res = 1;
184979119Sbrian          break;
185040622Sbrian        }
185140622Sbrian        break;
185240622Sbrian      default:
185340622Sbrian        log_Printf(LogWARN, "mrru: Only changable at phase DEAD/ESTABLISH\n");
185479119Sbrian        res = 1;
185579119Sbrian        break;
185629696Sbrian    }
185779119Sbrian    if (res != 0)
185879119Sbrian      break;
185937210Sbrian    long_val = atol(argp);
186037210Sbrian    if (long_val && long_val < MIN_MRU) {
186137210Sbrian      log_Printf(LogWARN, "MRRU %ld: too small - min %d\n", long_val, MIN_MRU);
186279119Sbrian      res = 1;
186379119Sbrian      break;
186437210Sbrian    } else if (long_val > MAX_MRU) {
186537210Sbrian      log_Printf(LogWARN, "MRRU %ld: too big - max %d\n", long_val, MAX_MRU);
186679119Sbrian      res = 1;
186779119Sbrian      break;
186837210Sbrian    } else
186937210Sbrian      arg->bundle->ncp.mp.cfg.mrru = long_val;
187028679Sbrian    break;
187137210Sbrian
187236285Sbrian  case VAR_MRU:
187379163Sbrian    long_val = 0;	/* silence gcc */
187479163Sbrian    change = NULL;	/* silence gcc */
187578410Sbrian    switch(arg->argc - arg->argn) {
187678410Sbrian    case 1:
187779119Sbrian      if (argp[strspn(argp, "0123456789")] != '\0') {
187879119Sbrian        res = -1;
187979119Sbrian        break;
188079119Sbrian      }
188179119Sbrian      /*FALLTHRU*/
188278410Sbrian    case 0:
188378410Sbrian      long_val = atol(argp);
188478410Sbrian      change = &l->lcp.cfg.mru;
188578410Sbrian      if (long_val > l->lcp.cfg.max_mru) {
188678410Sbrian        log_Printf(LogWARN, "MRU %ld: too large - max set to %d\n", long_val,
188778410Sbrian                   l->lcp.cfg.max_mru);
188879119Sbrian        res = 1;
188979119Sbrian        break;
189078410Sbrian      }
189178410Sbrian      break;
189278410Sbrian    case 2:
189379119Sbrian      if (strcasecmp(argp, "max") && strcasecmp(argp, "maximum")) {
189479119Sbrian        res = -1;
189579119Sbrian        break;
189679119Sbrian      }
189778410Sbrian      long_val = atol(arg->argv[arg->argn + 1]);
189878410Sbrian      change = &l->lcp.cfg.max_mru;
189978410Sbrian      if (long_val > MAX_MRU) {
190078410Sbrian        log_Printf(LogWARN, "MRU %ld: too large - maximum is %d\n", long_val,
190178410Sbrian                   MAX_MRU);
190279119Sbrian        res = 1;
190379119Sbrian        break;
190478410Sbrian      }
190578410Sbrian      break;
190678410Sbrian    default:
190779119Sbrian      res = -1;
190879119Sbrian      break;
190978410Sbrian    }
191079119Sbrian    if (res != 0)
191179119Sbrian      break;
191278410Sbrian
191337210Sbrian    if (long_val == 0)
191480385Sbrian      *change = 0;
191537210Sbrian    else if (long_val < MIN_MRU) {
191637210Sbrian      log_Printf(LogWARN, "MRU %ld: too small - min %d\n", long_val, MIN_MRU);
191779119Sbrian      res = 1;
191879119Sbrian      break;
191937210Sbrian    } else if (long_val > MAX_MRU) {
192037210Sbrian      log_Printf(LogWARN, "MRU %ld: too big - max %d\n", long_val, MAX_MRU);
192179119Sbrian      res = 1;
192279119Sbrian      break;
192337210Sbrian    } else
192478410Sbrian      *change = long_val;
192578410Sbrian    if (l->lcp.cfg.mru > *change)
192678410Sbrian      l->lcp.cfg.mru = *change;
192728679Sbrian    break;
192837210Sbrian
192936285Sbrian  case VAR_MTU:
193079163Sbrian    long_val = 0;	/* silence gcc */
193179163Sbrian    change = NULL;	/* silence gcc */
193278410Sbrian    switch(arg->argc - arg->argn) {
193378410Sbrian    case 1:
193479119Sbrian      if (argp[strspn(argp, "0123456789")] != '\0') {
193579119Sbrian        res = -1;
193679119Sbrian        break;
193779119Sbrian      }
193879119Sbrian      /*FALLTHRU*/
193978410Sbrian    case 0:
194078410Sbrian      long_val = atol(argp);
194178410Sbrian      change = &l->lcp.cfg.mtu;
194278410Sbrian      if (long_val > l->lcp.cfg.max_mtu) {
194378410Sbrian        log_Printf(LogWARN, "MTU %ld: too large - max set to %d\n", long_val,
194478410Sbrian                   l->lcp.cfg.max_mtu);
194579119Sbrian        res = 1;
194679119Sbrian        break;
194778410Sbrian      }
194878410Sbrian      break;
194978410Sbrian    case 2:
195079119Sbrian      if (strcasecmp(argp, "max") && strcasecmp(argp, "maximum")) {
195179119Sbrian        res = -1;
195279119Sbrian        break;
195379119Sbrian      }
195478410Sbrian      long_val = atol(arg->argv[arg->argn + 1]);
195578410Sbrian      change = &l->lcp.cfg.max_mtu;
195678410Sbrian      if (long_val > MAX_MTU) {
195778410Sbrian        log_Printf(LogWARN, "MTU %ld: too large - maximum is %d\n", long_val,
195878410Sbrian                   MAX_MTU);
195979119Sbrian        res = 1;
196079119Sbrian        break;
196178410Sbrian      }
196278410Sbrian      break;
196378410Sbrian    default:
196479119Sbrian      res = -1;
196579119Sbrian      break;
196678410Sbrian    }
196778410Sbrian
196879119Sbrian    if (res != 0)
196979119Sbrian      break;
197079119Sbrian
197137210Sbrian    if (long_val && long_val < MIN_MTU) {
197237210Sbrian      log_Printf(LogWARN, "MTU %ld: too small - min %d\n", long_val, MIN_MTU);
197379119Sbrian      res = 1;
197479119Sbrian      break;
197537210Sbrian    } else if (long_val > MAX_MTU) {
197637210Sbrian      log_Printf(LogWARN, "MTU %ld: too big - max %d\n", long_val, MAX_MTU);
197779119Sbrian      res = 1;
197879119Sbrian      break;
197937210Sbrian    } else
198078410Sbrian      *change = long_val;
198178410Sbrian    if (l->lcp.cfg.mtu > *change)
198278410Sbrian      l->lcp.cfg.mtu = *change;
198336285Sbrian    break;
198437210Sbrian
198536285Sbrian  case VAR_OPENMODE:
198636285Sbrian    if (strcasecmp(argp, "active") == 0)
198736285Sbrian      cx->physical->link.lcp.cfg.openmode = arg->argc > arg->argn+1 ?
198836285Sbrian        atoi(arg->argv[arg->argn+1]) : 1;
198936285Sbrian    else if (strcasecmp(argp, "passive") == 0)
199036285Sbrian      cx->physical->link.lcp.cfg.openmode = OPEN_PASSIVE;
199136285Sbrian    else {
199279119Sbrian      log_Printf(LogWARN, "%s: Invalid openmode\n", argp);
199379119Sbrian      res = 1;
199436285Sbrian    }
199536285Sbrian    break;
199637210Sbrian
199728679Sbrian  case VAR_PHONE:
199836285Sbrian    strncpy(cx->cfg.phone.list, argp, sizeof cx->cfg.phone.list - 1);
199936285Sbrian    cx->cfg.phone.list[sizeof cx->cfg.phone.list - 1] = '\0';
200038174Sbrian    cx->phone.alt = cx->phone.next = NULL;
200128679Sbrian    break;
200237210Sbrian
200328679Sbrian  case VAR_HANGUP:
200436285Sbrian    strncpy(cx->cfg.script.hangup, argp, sizeof cx->cfg.script.hangup - 1);
200536285Sbrian    cx->cfg.script.hangup[sizeof cx->cfg.script.hangup - 1] = '\0';
200628679Sbrian    break;
200737210Sbrian
200861534Sbrian  case VAR_IFQUEUE:
200961534Sbrian    long_val = atol(argp);
201061534Sbrian    arg->bundle->cfg.ifqueue = long_val < 0 ? 0 : long_val;
201161534Sbrian    break;
201261534Sbrian
201352488Sbrian  case VAR_LOGOUT:
201452488Sbrian    strncpy(cx->cfg.script.logout, argp, sizeof cx->cfg.script.logout - 1);
201552488Sbrian    cx->cfg.script.logout[sizeof cx->cfg.script.logout - 1] = '\0';
201652488Sbrian    break;
201752488Sbrian
201836285Sbrian  case VAR_IDLETIMEOUT:
201979119Sbrian    if (arg->argc > arg->argn+2) {
202079119Sbrian      log_Printf(LogWARN, "Too many idle timeout values\n");
202179119Sbrian      res = 1;
202279119Sbrian    } else if (arg->argc == arg->argn) {
202379119Sbrian      log_Printf(LogWARN, "Too few idle timeout values\n");
202479119Sbrian      res = 1;
202579119Sbrian    } else {
2026134789Sbrian      unsigned long timeout, min;
202749978Sbrian
2028134789Sbrian      timeout = strtoul(argp, NULL, 10);
2029134789Sbrian      min = arg->bundle->cfg.idle.min_timeout;
2030134789Sbrian      if (arg->argc == arg->argn + 2)
2031134789Sbrian	min = strtoul(arg->argv[arg->argn + 1], NULL, 10);
203249978Sbrian      bundle_SetIdleTimer(arg->bundle, timeout, min);
203349978Sbrian    }
203429549Sbrian    break;
2035132273Sbrian
2036132273Sbrian#ifndef NORADIUS
2037132273Sbrian  case VAR_RAD_ALIVE:
2038132273Sbrian    if (arg->argc > arg->argn + 2) {
2039132273Sbrian      log_Printf(LogWARN, "Too many RADIUS alive interval values\n");
2040132273Sbrian      res = 1;
2041132273Sbrian    } else if (arg->argc == arg->argn) {
2042132273Sbrian      log_Printf(LogWARN, "Too few RADIUS alive interval values\n");
2043132273Sbrian      res = 1;
2044132273Sbrian    } else {
2045132273Sbrian      arg->bundle->radius.alive.interval = atoi(argp);
2046132273Sbrian      if (arg->bundle->radius.alive.interval && !arg->bundle->radius.cfg.file) {
2047132273Sbrian        log_Printf(LogWARN, "rad_alive requires radius to be configured\n");
2048132273Sbrian	res = 1;
2049132273Sbrian      } else if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED) {
2050132273Sbrian	if (arg->bundle->radius.alive.interval)
2051132273Sbrian	  radius_StartTimer(arg->bundle);
2052132273Sbrian	else
2053132273Sbrian	  radius_StopTimer(&arg->bundle->radius);
2054132273Sbrian      }
2055132273Sbrian    }
2056132273Sbrian    break;
2057132273Sbrian#endif
2058132273Sbrian
205936285Sbrian  case VAR_LQRPERIOD:
206037210Sbrian    long_val = atol(argp);
206137210Sbrian    if (long_val < MIN_LQRPERIOD) {
206237210Sbrian      log_Printf(LogWARN, "%ld: Invalid lqr period - min %d\n",
206337210Sbrian                 long_val, MIN_LQRPERIOD);
206479119Sbrian      res = 1;
206536285Sbrian    } else
206637210Sbrian      l->lcp.cfg.lqrperiod = long_val;
206736285Sbrian    break;
206837210Sbrian
206936285Sbrian  case VAR_LCPRETRY:
207079119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
207179119Sbrian                   &cx->physical->link.lcp.cfg.fsm.timeout,
207279119Sbrian                   &cx->physical->link.lcp.cfg.fsm.maxreq,
207379119Sbrian                   &cx->physical->link.lcp.cfg.fsm.maxtrm, DEF_FSMTRIES);
207436285Sbrian    break;
207537210Sbrian
207636285Sbrian  case VAR_CHAPRETRY:
207779119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
207879119Sbrian                   &cx->chap.auth.cfg.fsm.timeout,
207979119Sbrian                   &cx->chap.auth.cfg.fsm.maxreq, NULL, DEF_FSMAUTHTRIES);
208036285Sbrian    break;
208137210Sbrian
208236285Sbrian  case VAR_PAPRETRY:
208379119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
208479119Sbrian                   &cx->pap.cfg.fsm.timeout, &cx->pap.cfg.fsm.maxreq,
208579119Sbrian                   NULL, DEF_FSMAUTHTRIES);
208636285Sbrian    break;
208737210Sbrian
208836285Sbrian  case VAR_CCPRETRY:
208979119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
209079119Sbrian                   &l->ccp.cfg.fsm.timeout, &l->ccp.cfg.fsm.maxreq,
209179119Sbrian                   &l->ccp.cfg.fsm.maxtrm, DEF_FSMTRIES);
209236285Sbrian    break;
209337210Sbrian
209436285Sbrian  case VAR_IPCPRETRY:
209579119Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
209679119Sbrian                   &arg->bundle->ncp.ipcp.cfg.fsm.timeout,
209779119Sbrian                   &arg->bundle->ncp.ipcp.cfg.fsm.maxreq,
209879119Sbrian                   &arg->bundle->ncp.ipcp.cfg.fsm.maxtrm, DEF_FSMTRIES);
209936285Sbrian    break;
210037210Sbrian
2101102855Sbrian#ifndef NOINET6
2102102558Sbrian  case VAR_IPV6CPRETRY:
2103102558Sbrian    res = SetRetry(arg->argc - arg->argn, arg->argv + arg->argn,
2104102558Sbrian                   &arg->bundle->ncp.ipv6cp.cfg.fsm.timeout,
2105102558Sbrian                   &arg->bundle->ncp.ipv6cp.cfg.fsm.maxreq,
2106102558Sbrian                   &arg->bundle->ncp.ipv6cp.cfg.fsm.maxtrm, DEF_FSMTRIES);
2107102558Sbrian    break;
2108102855Sbrian#endif
2109102558Sbrian
211036285Sbrian  case VAR_NBNS:
211136285Sbrian  case VAR_DNS:
211258044Sbrian    if (param == VAR_DNS) {
211381634Sbrian      ipaddr = arg->bundle->ncp.ipcp.cfg.ns.dns;
211481634Sbrian      ipaddr[0].s_addr = ipaddr[1].s_addr = INADDR_NONE;
211558044Sbrian    } else {
211681634Sbrian      ipaddr = arg->bundle->ncp.ipcp.cfg.ns.nbns;
211781634Sbrian      ipaddr[0].s_addr = ipaddr[1].s_addr = INADDR_ANY;
211858044Sbrian    }
211936285Sbrian
212036285Sbrian    if (arg->argc > arg->argn) {
212181634Sbrian      ncpaddr_aton(ncpaddr, &arg->bundle->ncp, arg->argv[arg->argn]);
212281634Sbrian      if (!ncpaddr_getip4(ncpaddr, ipaddr))
212381634Sbrian        return -1;
212481634Sbrian      if (arg->argc > arg->argn+1) {
212581634Sbrian        ncpaddr_aton(ncpaddr + 1, &arg->bundle->ncp, arg->argv[arg->argn + 1]);
212681634Sbrian        if (!ncpaddr_getip4(ncpaddr + 1, ipaddr + 1))
212781634Sbrian          return -1;
212881634Sbrian      }
212936285Sbrian
213081634Sbrian      if (ipaddr[0].s_addr == INADDR_ANY) {
213181634Sbrian        ipaddr[0] = ipaddr[1];
213281634Sbrian        ipaddr[1].s_addr = INADDR_ANY;
213358044Sbrian      }
213481634Sbrian      if (ipaddr[0].s_addr == INADDR_NONE) {
213581634Sbrian        ipaddr[0] = ipaddr[1];
213681634Sbrian        ipaddr[1].s_addr = INADDR_NONE;
213758044Sbrian      }
213836285Sbrian    }
213936285Sbrian    break;
214038174Sbrian
214138174Sbrian  case VAR_CALLBACK:
214238174Sbrian    cx->cfg.callback.opmask = 0;
214338174Sbrian    for (dummyint = arg->argn; dummyint < arg->argc; dummyint++) {
214438174Sbrian      if (!strcasecmp(arg->argv[dummyint], "auth"))
214538174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_AUTH);
214638174Sbrian      else if (!strcasecmp(arg->argv[dummyint], "cbcp"))
214738174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_CBCP);
214838174Sbrian      else if (!strcasecmp(arg->argv[dummyint], "e.164")) {
214938174Sbrian        if (dummyint == arg->argc - 1)
215038174Sbrian          log_Printf(LogWARN, "No E.164 arg (E.164 ignored) !\n");
215138174Sbrian        else {
215238174Sbrian          cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_E164);
215338174Sbrian          strncpy(cx->cfg.callback.msg, arg->argv[++dummyint],
215438174Sbrian                  sizeof cx->cfg.callback.msg - 1);
215538174Sbrian          cx->cfg.callback.msg[sizeof cx->cfg.callback.msg - 1] = '\0';
215638174Sbrian        }
215738174Sbrian      } else if (!strcasecmp(arg->argv[dummyint], "none"))
215838174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_NONE);
215979119Sbrian      else {
216079119Sbrian        res = -1;
216179119Sbrian        break;
216279119Sbrian      }
216338174Sbrian    }
216438174Sbrian    if (cx->cfg.callback.opmask == CALLBACK_BIT(CALLBACK_NONE))
216538174Sbrian      cx->cfg.callback.opmask = 0;
216638174Sbrian    break;
216738174Sbrian
216838174Sbrian  case VAR_CBCP:
216938174Sbrian    cx->cfg.cbcp.delay = 0;
217038174Sbrian    *cx->cfg.cbcp.phone = '\0';
217138174Sbrian    cx->cfg.cbcp.fsmretry = DEF_FSMRETRY;
217238174Sbrian    if (arg->argc > arg->argn) {
217338174Sbrian      strncpy(cx->cfg.cbcp.phone, arg->argv[arg->argn],
217438174Sbrian              sizeof cx->cfg.cbcp.phone - 1);
217538174Sbrian      cx->cfg.cbcp.phone[sizeof cx->cfg.cbcp.phone - 1] = '\0';
217638174Sbrian      if (arg->argc > arg->argn + 1) {
217738174Sbrian        cx->cfg.cbcp.delay = atoi(arg->argv[arg->argn + 1]);
217838174Sbrian        if (arg->argc > arg->argn + 2) {
217938174Sbrian          long_val = atol(arg->argv[arg->argn + 2]);
218038174Sbrian          if (long_val < MIN_FSMRETRY)
218138174Sbrian            log_Printf(LogWARN, "%ld: Invalid CBCP FSM retry period - min %d\n",
218238174Sbrian                       long_val, MIN_FSMRETRY);
218338174Sbrian          else
218438174Sbrian            cx->cfg.cbcp.fsmretry = long_val;
218538174Sbrian        }
218638174Sbrian      }
218738174Sbrian    }
218838174Sbrian    break;
218938544Sbrian
219038544Sbrian  case VAR_CHOKED:
219138544Sbrian    arg->bundle->cfg.choked.timeout = atoi(argp);
219238544Sbrian    if (arg->bundle->cfg.choked.timeout <= 0)
219338544Sbrian      arg->bundle->cfg.choked.timeout = CHOKED_TIMEOUT;
219438544Sbrian    break;
219540665Sbrian
219640665Sbrian  case VAR_SENDPIPE:
219740665Sbrian    long_val = atol(argp);
219881634Sbrian    arg->bundle->ncp.cfg.sendpipe = long_val;
219940665Sbrian    break;
220040665Sbrian
220140665Sbrian  case VAR_RECVPIPE:
220240665Sbrian    long_val = atol(argp);
220381634Sbrian    arg->bundle->ncp.cfg.recvpipe = long_val;
220440665Sbrian    break;
220543313Sbrian
220643313Sbrian#ifndef NORADIUS
220743313Sbrian  case VAR_RADIUS:
220843313Sbrian    if (!*argp)
220943313Sbrian      *arg->bundle->radius.cfg.file = '\0';
221043313Sbrian    else if (access(argp, R_OK)) {
221143313Sbrian      log_Printf(LogWARN, "%s: %s\n", argp, strerror(errno));
221279119Sbrian      res = 1;
221379119Sbrian      break;
221443313Sbrian    } else {
221543313Sbrian      strncpy(arg->bundle->radius.cfg.file, argp,
221643313Sbrian              sizeof arg->bundle->radius.cfg.file - 1);
221743313Sbrian      arg->bundle->radius.cfg.file
221843313Sbrian        [sizeof arg->bundle->radius.cfg.file - 1] = '\0';
221943313Sbrian    }
222043313Sbrian    break;
222143313Sbrian#endif
222244073Sbrian
222344073Sbrian  case VAR_CD:
222444073Sbrian    if (*argp) {
222551699Sbrian      if (strcasecmp(argp, "off")) {
222651699Sbrian        long_val = atol(argp);
222751699Sbrian        if (long_val < 0)
222851699Sbrian          long_val = 0;
222951699Sbrian        cx->physical->cfg.cd.delay = long_val;
223051699Sbrian        cx->physical->cfg.cd.necessity = argp[strlen(argp)-1] == '!' ?
223151699Sbrian          CD_REQUIRED : CD_VARIABLE;
223251699Sbrian      } else
223351699Sbrian        cx->physical->cfg.cd.necessity = CD_NOTREQUIRED;
223444073Sbrian    } else {
223553733Sbrian      cx->physical->cfg.cd.delay = 0;
223653733Sbrian      cx->physical->cfg.cd.necessity = CD_DEFAULT;
223744073Sbrian    }
223844073Sbrian    break;
223936285Sbrian
224046686Sbrian  case VAR_PARITY:
224146686Sbrian    if (arg->argc == arg->argn + 1)
224279119Sbrian      res = physical_SetParity(arg->cx->physical, argp);
224346686Sbrian    else {
224479119Sbrian      log_Printf(LogWARN, "Parity value must be odd, even or none\n");
224579119Sbrian      res = 1;
224646686Sbrian    }
224746686Sbrian    break;
22486059Samurai
224946686Sbrian  case VAR_CRTSCTS:
225046686Sbrian    if (strcasecmp(argp, "on") == 0)
225136285Sbrian      physical_SetRtsCts(arg->cx->physical, 1);
225246686Sbrian    else if (strcasecmp(argp, "off") == 0)
225336285Sbrian      physical_SetRtsCts(arg->cx->physical, 0);
225446686Sbrian    else {
225579119Sbrian      log_Printf(LogWARN, "RTS/CTS value must be on or off\n");
225679119Sbrian      res = 1;
225746686Sbrian    }
225846686Sbrian    break;
225950867Sbrian
226050867Sbrian  case VAR_URGENTPORTS:
226151048Sbrian    if (arg->argn == arg->argc) {
226281634Sbrian      ncp_SetUrgentTOS(&arg->bundle->ncp);
226381634Sbrian      ncp_ClearUrgentTcpPorts(&arg->bundle->ncp);
226481634Sbrian      ncp_ClearUrgentUdpPorts(&arg->bundle->ncp);
226551048Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "udp")) {
226681634Sbrian      ncp_SetUrgentTOS(&arg->bundle->ncp);
226751048Sbrian      if (arg->argn == arg->argc - 1)
226881634Sbrian        ncp_ClearUrgentUdpPorts(&arg->bundle->ncp);
226951048Sbrian      else for (f = arg->argn + 1; f < arg->argc; f++)
227051048Sbrian        if (*arg->argv[f] == '+')
227181634Sbrian          ncp_AddUrgentUdpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1));
227251048Sbrian        else if (*arg->argv[f] == '-')
227381634Sbrian          ncp_RemoveUrgentUdpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1));
227451048Sbrian        else {
227551048Sbrian          if (f == arg->argn)
227681634Sbrian            ncp_ClearUrgentUdpPorts(&arg->bundle->ncp);
227781634Sbrian          ncp_AddUrgentUdpPort(&arg->bundle->ncp, atoi(arg->argv[f]));
227851048Sbrian        }
227961430Sbrian    } else if (arg->argn == arg->argc - 1 &&
228061430Sbrian               !strcasecmp(arg->argv[arg->argn], "none")) {
228181634Sbrian      ncp_ClearUrgentTcpPorts(&arg->bundle->ncp);
228281634Sbrian      ncp_ClearUrgentUdpPorts(&arg->bundle->ncp);
228381634Sbrian      ncp_ClearUrgentTOS(&arg->bundle->ncp);
228451048Sbrian    } else {
228581634Sbrian      ncp_SetUrgentTOS(&arg->bundle->ncp);
228651048Sbrian      first = arg->argn;
228751048Sbrian      if (!strcasecmp(arg->argv[first], "tcp") && ++first == arg->argc)
228881634Sbrian        ncp_ClearUrgentTcpPorts(&arg->bundle->ncp);
228951048Sbrian
229051048Sbrian      for (f = first; f < arg->argc; f++)
229151048Sbrian        if (*arg->argv[f] == '+')
229281634Sbrian          ncp_AddUrgentTcpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1));
229351048Sbrian        else if (*arg->argv[f] == '-')
229481634Sbrian          ncp_RemoveUrgentTcpPort(&arg->bundle->ncp, atoi(arg->argv[f] + 1));
229551048Sbrian        else {
229651048Sbrian          if (f == first)
229781634Sbrian            ncp_ClearUrgentTcpPorts(&arg->bundle->ncp);
229881634Sbrian          ncp_AddUrgentTcpPort(&arg->bundle->ncp, atoi(arg->argv[f]));
229951048Sbrian        }
230051048Sbrian    }
230150867Sbrian    break;
2302132818Sglebius
2303132818Sglebius  case VAR_PPPOE:
2304132818Sglebius    if (strcasecmp(argp, "3Com") == 0)
2305132818Sglebius      physical_SetPPPoEnonstandard(arg->cx->physical, 1);
2306132818Sglebius    else if (strcasecmp(argp, "standard") == 0)
2307132818Sglebius      physical_SetPPPoEnonstandard(arg->cx->physical, 0);
2308132818Sglebius    else {
2309132818Sglebius      log_Printf(LogWARN, "PPPoE standard value must be \"standard\" or \"3Com\"\n");
2310132818Sglebius      res = 1;
2311132818Sglebius    }
2312132818Sglebius    break;
2313132818Sglebius
231420812Sjkh  }
231546686Sbrian
231679119Sbrian  return res;
231720812Sjkh}
231820812Sjkh
231930715Sbrianstatic struct cmdtab const SetCommands[] = {
232036285Sbrian  {"accmap", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
232136285Sbrian  "accmap value", "set accmap hex-value", (const void *)VAR_ACCMAP},
232228679Sbrian  {"authkey", "key", SetVariable, LOCAL_AUTH,
232336285Sbrian  "authentication key", "set authkey|key key", (const void *)VAR_AUTHKEY},
232428679Sbrian  {"authname", NULL, SetVariable, LOCAL_AUTH,
232536285Sbrian  "authentication name", "set authname name", (const void *)VAR_AUTHNAME},
232636285Sbrian  {"autoload", NULL, SetVariable, LOCAL_AUTH,
232736285Sbrian  "auto link [de]activation", "set autoload maxtime maxload mintime minload",
232836285Sbrian  (const void *)VAR_AUTOLOAD},
232950867Sbrian  {"bandwidth", NULL, mp_SetDatalinkBandwidth, LOCAL_AUTH | LOCAL_CX,
2330134789Sbrian  "datalink bandwidth", "set bandwidth value", NULL},
233138174Sbrian  {"callback", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
233238174Sbrian  "callback control", "set callback [none|auth|cbcp|"
233338174Sbrian  "E.164 *|number[,number]...]...", (const void *)VAR_CALLBACK},
233438174Sbrian  {"cbcp", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
233598243Sbrian  "CBCP control", "set cbcp [*|phone[,phone...] [delay [timeout]]]",
233638174Sbrian  (const void *)VAR_CBCP},
233744305Sbrian  {"ccpretry", "ccpretries", SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
233844305Sbrian   "CCP retries", "set ccpretry value [attempts]", (const void *)VAR_CCPRETRY},
233944073Sbrian  {"cd", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "Carrier delay requirement",
234044073Sbrian   "set cd value[!]", (const void *)VAR_CD},
234144305Sbrian  {"chapretry", "chapretries", SetVariable, LOCAL_AUTH | LOCAL_CX,
234244305Sbrian   "CHAP retries", "set chapretry value [attempts]",
234344305Sbrian   (const void *)VAR_CHAPRETRY},
234438544Sbrian  {"choked", NULL, SetVariable, LOCAL_AUTH,
234538544Sbrian  "choked timeout", "set choked [secs]", (const void *)VAR_CHOKED},
234646686Sbrian  {"ctsrts", "crtscts", SetVariable, LOCAL_AUTH | LOCAL_CX,
234746686Sbrian   "Use hardware flow control", "set ctsrts [on|off]",
234846686Sbrian   (const char *)VAR_CRTSCTS},
234936285Sbrian  {"deflate", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
235036285Sbrian  "deflate window sizes", "set deflate out-winsize in-winsize",
235136285Sbrian  (const void *) VAR_WINSIZE},
235293418Sbrian#ifndef NODES
235367910Sbrian  {"mppe", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
235498243Sbrian  "MPPE key size and state", "set mppe [40|56|128|* [stateful|stateless|*]]",
235578411Sbrian  (const void *) VAR_MPPE},
235667910Sbrian#endif
235736285Sbrian  {"device", "line", SetVariable, LOCAL_AUTH | LOCAL_CX,
235846686Sbrian  "physical device name", "set device|line device-name[,device-name]",
235936285Sbrian  (const void *) VAR_DEVICE},
236036285Sbrian  {"dial", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
236136285Sbrian  "dialing script", "set dial chat-script", (const void *) VAR_DIAL},
236236285Sbrian  {"dns", NULL, SetVariable, LOCAL_AUTH, "Domain Name Server",
236336285Sbrian  "set dns pri-addr [sec-addr]", (const void *)VAR_DNS},
236436285Sbrian  {"enddisc", NULL, mp_SetEnddisc, LOCAL_AUTH,
2365134789Sbrian  "Endpoint Discriminator", "set enddisc [IP|magic|label|psn value]", NULL},
236636285Sbrian  {"escape", NULL, SetEscape, LOCAL_AUTH | LOCAL_CX,
2367134789Sbrian  "escape characters", "set escape hex-digit ...", NULL},
236836285Sbrian  {"filter", NULL, filter_Set, LOCAL_AUTH,
236936285Sbrian  "packet filters", "set filter alive|dial|in|out rule-no permit|deny "
237081634Sbrian  "[src_addr[/width]] [dst_addr[/width]] [proto "
2371134789Sbrian  "[src [lt|eq|gt port]] [dst [lt|eq|gt port]] [estab] [syn] [finrst]]", NULL},
237236285Sbrian  {"hangup", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
237336285Sbrian  "hangup script", "set hangup chat-script", (const void *) VAR_HANGUP},
237436285Sbrian  {"ifaddr", NULL, SetInterfaceAddr, LOCAL_AUTH, "destination address",
2375134789Sbrian  "set ifaddr [src-addr [dst-addr [netmask [trg-addr]]]]", NULL},
237661534Sbrian  {"ifqueue", NULL, SetVariable, LOCAL_AUTH, "interface queue",
237761534Sbrian  "set ifqueue packets", (const void *)VAR_IFQUEUE},
237844305Sbrian  {"ipcpretry", "ipcpretries", SetVariable, LOCAL_AUTH, "IPCP retries",
237944305Sbrian   "set ipcpretry value [attempts]", (const void *)VAR_IPCPRETRY},
2380102558Sbrian  {"ipv6cpretry", "ipv6cpretries", SetVariable, LOCAL_AUTH, "IPV6CP retries",
2381102558Sbrian   "set ipv6cpretry value [attempts]", (const void *)VAR_IPV6CPRETRY},
238244305Sbrian  {"lcpretry", "lcpretries", SetVariable, LOCAL_AUTH | LOCAL_CX, "LCP retries",
238344305Sbrian   "set lcpretry value [attempts]", (const void *)VAR_LCPRETRY},
238436712Sbrian  {"log", NULL, log_SetLevel, LOCAL_AUTH, "log level",
238567916Sbrian  "set log [local] [+|-]all|async|cbcp|ccp|chat|command|connect|debug|dns|hdlc|"
2386134789Sbrian  "id0|ipcp|lcp|lqm|phase|physical|radius|sync|tcp/ip|timer|tun...", NULL},
238736285Sbrian  {"login", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
238836285Sbrian  "login script", "set login chat-script", (const void *) VAR_LOGIN},
238952488Sbrian  {"logout", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
239052488Sbrian  "logout script", "set logout chat-script", (const void *) VAR_LOGOUT},
239136285Sbrian  {"lqrperiod", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
239236285Sbrian  "LQR period", "set lqrperiod value", (const void *)VAR_LQRPERIOD},
239336285Sbrian  {"mode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "mode value",
239436285Sbrian  "set mode interactive|auto|ddial|background", (const void *)VAR_MODE},
239536285Sbrian  {"mrru", NULL, SetVariable, LOCAL_AUTH, "MRRU value",
239636285Sbrian  "set mrru value", (const void *)VAR_MRRU},
239796038Sbrian  {"mru", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
239878410Sbrian  "MRU value", "set mru [max[imum]] [value]", (const void *)VAR_MRU},
239978410Sbrian  {"mtu", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
240078410Sbrian  "interface MTU value", "set mtu [max[imum]] [value]", (const void *)VAR_MTU},
240136285Sbrian  {"nbns", NULL, SetVariable, LOCAL_AUTH, "NetBIOS Name Server",
240236285Sbrian  "set nbns pri-addr [sec-addr]", (const void *)VAR_NBNS},
240336285Sbrian  {"openmode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "open mode",
240436285Sbrian  "set openmode active|passive [secs]", (const void *)VAR_OPENMODE},
240544305Sbrian  {"papretry", "papretries", SetVariable, LOCAL_AUTH | LOCAL_CX, "PAP retries",
240644305Sbrian   "set papretry value [attempts]", (const void *)VAR_PAPRETRY},
240746686Sbrian  {"parity", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "serial parity",
240846686Sbrian   "set parity [odd|even|none]", (const void *)VAR_PARITY},
240936285Sbrian  {"phone", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "telephone number(s)",
241036285Sbrian  "set phone phone1[:phone2[...]]", (const void *)VAR_PHONE},
241140679Sbrian  {"proctitle", "title", SetProcTitle, LOCAL_AUTH,
2412134789Sbrian  "Process title", "set proctitle [value]", NULL},
241343313Sbrian#ifndef NORADIUS
241443313Sbrian  {"radius", NULL, SetVariable, LOCAL_AUTH,
241543313Sbrian  "RADIUS Config", "set radius cfgfile", (const void *)VAR_RADIUS},
2416132273Sbrian  {"rad_alive", NULL, SetVariable, LOCAL_AUTH,
2417132273Sbrian  "Raduis alive interval", "set rad_alive value",
2418132273Sbrian  (const void *)VAR_RAD_ALIVE},
241943313Sbrian#endif
242036285Sbrian  {"reconnect", NULL, datalink_SetReconnect, LOCAL_AUTH | LOCAL_CX,
2421134789Sbrian  "Reconnect timeout", "set reconnect value ntries", NULL},
242240665Sbrian  {"recvpipe", NULL, SetVariable, LOCAL_AUTH,
242340665Sbrian  "RECVPIPE value", "set recvpipe value", (const void *)VAR_RECVPIPE},
242436285Sbrian  {"redial", NULL, datalink_SetRedial, LOCAL_AUTH | LOCAL_CX,
2425134789Sbrian  "Redial timeout", "set redial secs[+inc[-incmax]][.next] [attempts]", NULL},
242640665Sbrian  {"sendpipe", NULL, SetVariable, LOCAL_AUTH,
242740665Sbrian  "SENDPIPE value", "set sendpipe value", (const void *)VAR_SENDPIPE},
242871657Sbrian  {"server", "socket", SetServer, LOCAL_AUTH, "diagnostic port",
2429134789Sbrian  "set server|socket TcpPort|LocalName|none|open|closed [password [mask]]",
2430134789Sbrian  NULL},
243136285Sbrian  {"speed", NULL, SetModemSpeed, LOCAL_AUTH | LOCAL_CX,
2432134789Sbrian  "physical speed", "set speed value|sync", NULL},
243336285Sbrian  {"stopped", NULL, SetStoppedTimeout, LOCAL_AUTH | LOCAL_CX,
2434134789Sbrian  "STOPPED timeouts", "set stopped [LCPseconds [CCPseconds]]", NULL},
243536285Sbrian  {"timeout", NULL, SetVariable, LOCAL_AUTH, "Idle timeout",
243636285Sbrian  "set timeout idletime", (const void *)VAR_IDLETIMEOUT},
243751048Sbrian  {"urgent", NULL, SetVariable, LOCAL_AUTH, "urgent ports",
243851048Sbrian  "set urgent [tcp|udp] [+|-]port...", (const void *)VAR_URGENTPORTS},
243936285Sbrian  {"vj", NULL, ipcp_vjset, LOCAL_AUTH,
2440134789Sbrian  "vj values", "set vj slots|slotcomp [value]", NULL},
244128679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
244231343Sbrian  "Display this message", "set help|? [command]", SetCommands},
2443132818Sglebius  {"pppoe", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
2444132818Sglebius   "Connect using standard/3Com mode", "set pppoe [standard|3Com]",
2445132818Sglebius   (const char *)VAR_PPPOE},
2446134789Sbrian  {NULL, NULL, NULL, 0, NULL, NULL, NULL},
24476059Samurai};
24486059Samurai
24496059Samuraistatic int
245031343SbrianSetCommand(struct cmdargs const *arg)
24516059Samurai{
245236285Sbrian  if (arg->argc > arg->argn)
245336285Sbrian    FindExec(arg->bundle, SetCommands, arg->argc, arg->argn, arg->argv,
245436285Sbrian             arg->prompt, arg->cx);
245536285Sbrian  else if (arg->prompt)
245636285Sbrian    prompt_Printf(arg->prompt, "Use `set ?' to get a list or `set ? <var>' for"
245758044Sbrian	          " syntax help.\n");
24586059Samurai  else
245936285Sbrian    log_Printf(LogWARN, "set command must have arguments\n");
246026516Sbrian
246126516Sbrian  return 0;
24626059Samurai}
24636059Samurai
24646059Samuraistatic int
246531343SbrianAddCommand(struct cmdargs const *arg)
24666059Samurai{
246781634Sbrian  struct ncpaddr gw;
246881634Sbrian  struct ncprange dest;
246981634Sbrian  struct in_addr host;
2470112673Sume#ifndef NOINET6
2471112673Sume  struct in6_addr host6;
2472112673Sume#endif
247381634Sbrian  int dest_default, gw_arg, addrs;
24746059Samurai
247536285Sbrian  if (arg->argc != arg->argn+3 && arg->argc != arg->argn+2)
247631598Sbrian    return -1;
247731598Sbrian
247836285Sbrian  addrs = 0;
247981634Sbrian  dest_default = 0;
248081634Sbrian  if (arg->argc == arg->argn + 2) {
248136285Sbrian    if (!strcasecmp(arg->argv[arg->argn], "default"))
248281634Sbrian      dest_default = 1;
248331598Sbrian    else {
248481634Sbrian      if (!ncprange_aton(&dest, &arg->bundle->ncp, arg->argv[arg->argn]))
248536285Sbrian        return -1;
248636285Sbrian      if (!strncasecmp(arg->argv[arg->argn], "MYADDR", 6))
248736285Sbrian        addrs = ROUTE_DSTMYADDR;
248881634Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "MYADDR6", 7))
248981634Sbrian        addrs = ROUTE_DSTMYADDR6;
249036285Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "HISADDR", 7))
249136285Sbrian        addrs = ROUTE_DSTHISADDR;
249281634Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "HISADDR6", 8))
249381634Sbrian        addrs = ROUTE_DSTHISADDR6;
249458044Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "DNS0", 4))
249558044Sbrian        addrs = ROUTE_DSTDNS0;
249658044Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "DNS1", 4))
249758044Sbrian        addrs = ROUTE_DSTDNS1;
249831598Sbrian    }
249981634Sbrian    gw_arg = 1;
250034536Sbrian  } else {
250136285Sbrian    if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
250236285Sbrian      addrs = ROUTE_DSTMYADDR;
250381634Sbrian      host = arg->bundle->ncp.ipcp.my_ip;
250436285Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
250536285Sbrian      addrs = ROUTE_DSTHISADDR;
250681634Sbrian      host = arg->bundle->ncp.ipcp.peer_ip;
250758044Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "DNS0") == 0) {
250858044Sbrian      addrs = ROUTE_DSTDNS0;
250981634Sbrian      host = arg->bundle->ncp.ipcp.ns.dns[0];
251058044Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "DNS1") == 0) {
251158044Sbrian      addrs = ROUTE_DSTDNS1;
251281634Sbrian      host = arg->bundle->ncp.ipcp.ns.dns[1];
251365263Sbrian    } else {
251481634Sbrian      host = GetIpAddr(arg->argv[arg->argn]);
251581634Sbrian      if (host.s_addr == INADDR_NONE) {
251665263Sbrian        log_Printf(LogWARN, "%s: Invalid destination address\n",
251765263Sbrian                   arg->argv[arg->argn]);
251865263Sbrian        return -1;
251965263Sbrian      }
252065263Sbrian    }
252181634Sbrian    ncprange_setip4(&dest, host, GetIpAddr(arg->argv[arg->argn + 1]));
252281634Sbrian    gw_arg = 2;
25236059Samurai  }
252436285Sbrian
252581634Sbrian  if (strcasecmp(arg->argv[arg->argn + gw_arg], "HISADDR") == 0) {
252681634Sbrian    ncpaddr_setip4(&gw, arg->bundle->ncp.ipcp.peer_ip);
252736285Sbrian    addrs |= ROUTE_GWHISADDR;
252881634Sbrian#ifndef NOINET6
252981897Sbrian  } else if (strcasecmp(arg->argv[arg->argn + gw_arg], "HISADDR6") == 0) {
2530112673Sume    if (!ncpaddr_getip6(&arg->bundle->ncp.ipv6cp.hisaddr, &host6))
2531112673Sume      memset(&host6, '\0', sizeof host6);
2532112673Sume    ncpaddr_setip6(&gw, &host6);
253381634Sbrian    addrs |= ROUTE_GWHISADDR6;
253481634Sbrian#endif
253565263Sbrian  } else {
253681634Sbrian    if (!ncpaddr_aton(&gw, &arg->bundle->ncp, arg->argv[arg->argn + gw_arg])) {
253765263Sbrian      log_Printf(LogWARN, "%s: Invalid gateway address\n",
253881634Sbrian                 arg->argv[arg->argn + gw_arg]);
253965263Sbrian      return -1;
254065263Sbrian    }
254165263Sbrian  }
254236285Sbrian
254381634Sbrian  if (dest_default)
254481634Sbrian    ncprange_setdefault(&dest, ncpaddr_family(&gw));
254581634Sbrian
254681634Sbrian  if (rt_Set(arg->bundle, RTM_ADD, &dest, &gw, arg->cmd->args ? 1 : 0,
254781634Sbrian             ((addrs & ROUTE_GWHISADDR) || (addrs & ROUTE_GWHISADDR6)) ? 1 : 0)
254843313Sbrian      && addrs != ROUTE_STATIC)
254981634Sbrian    route_Add(&arg->bundle->ncp.route, addrs, &dest, &gw);
255036285Sbrian
255131598Sbrian  return 0;
25526059Samurai}
25536059Samurai
25546059Samuraistatic int
255531343SbrianDeleteCommand(struct cmdargs const *arg)
25566059Samurai{
255781634Sbrian  struct ncprange dest;
255836285Sbrian  int addrs;
25596059Samurai
256036285Sbrian  if (arg->argc == arg->argn+1) {
256136285Sbrian    if(strcasecmp(arg->argv[arg->argn], "all") == 0) {
256236285Sbrian      route_IfDelete(arg->bundle, 0);
256381634Sbrian      route_DeleteAll(&arg->bundle->ncp.route);
256436285Sbrian    } else {
256536285Sbrian      addrs = 0;
256636285Sbrian      if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
256781634Sbrian        ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.my_ip);
256836285Sbrian        addrs = ROUTE_DSTMYADDR;
256981634Sbrian#ifndef NOINET6
257081897Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "MYADDR6") == 0) {
257181634Sbrian        ncprange_sethost(&dest, &arg->bundle->ncp.ipv6cp.myaddr);
257281634Sbrian        addrs = ROUTE_DSTMYADDR6;
257381634Sbrian#endif
257436285Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
257581634Sbrian        ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.peer_ip);
257636285Sbrian        addrs = ROUTE_DSTHISADDR;
257781634Sbrian#ifndef NOINET6
257881897Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "HISADDR6") == 0) {
257981634Sbrian        ncprange_sethost(&dest, &arg->bundle->ncp.ipv6cp.hisaddr);
258081634Sbrian        addrs = ROUTE_DSTHISADDR6;
258181634Sbrian#endif
258258044Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "DNS0") == 0) {
258381634Sbrian        ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.ns.dns[0]);
258458044Sbrian        addrs = ROUTE_DSTDNS0;
258558044Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "DNS1") == 0) {
258681634Sbrian        ncprange_setip4host(&dest, arg->bundle->ncp.ipcp.ns.dns[1]);
258758044Sbrian        addrs = ROUTE_DSTDNS1;
258836285Sbrian      } else {
258981634Sbrian        ncprange_aton(&dest, &arg->bundle->ncp, arg->argv[arg->argn]);
259036285Sbrian        addrs = ROUTE_STATIC;
259136285Sbrian      }
259281634Sbrian      rt_Set(arg->bundle, RTM_DELETE, &dest, NULL, arg->cmd->args ? 1 : 0, 0);
259381634Sbrian      route_Delete(&arg->bundle->ncp.route, addrs, &dest);
259431598Sbrian    }
259534536Sbrian  } else
259626516Sbrian    return -1;
259726516Sbrian
259826516Sbrian  return 0;
25996059Samurai}
26006059Samurai
260150059Sbrian#ifndef NONAT
260226031Sbrianstatic int
260358867SbrianNatEnable(struct cmdargs const *arg)
260426031Sbrian{
260536285Sbrian  if (arg->argc == arg->argn+1) {
260636285Sbrian    if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
260750059Sbrian      if (!arg->bundle->NatEnabled) {
260846686Sbrian        if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED)
260946686Sbrian          PacketAliasSetAddress(arg->bundle->ncp.ipcp.my_ip);
261050059Sbrian        arg->bundle->NatEnabled = 1;
261146686Sbrian      }
261237191Sbrian      return 0;
261336285Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "no") == 0) {
261450059Sbrian      arg->bundle->NatEnabled = 0;
261540561Sbrian      arg->bundle->cfg.opt &= ~OPT_IFACEALIAS;
261640561Sbrian      /* Don't iface_Clear() - there may be manually configured addresses */
261726516Sbrian      return 0;
261826142Sbrian    }
261935449Sbrian  }
262036285Sbrian
262126516Sbrian  return -1;
262226031Sbrian}
262326031Sbrian
262426031Sbrian
262526031Sbrianstatic int
262658867SbrianNatOption(struct cmdargs const *arg)
262726031Sbrian{
262838559Sbrian  long param = (long)arg->cmd->args;
262938559Sbrian
263036285Sbrian  if (arg->argc == arg->argn+1) {
263136285Sbrian    if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
263250059Sbrian      if (arg->bundle->NatEnabled) {
263337191Sbrian	PacketAliasSetMode(param, param);
263428679Sbrian	return 0;
263528679Sbrian      }
263650059Sbrian      log_Printf(LogWARN, "nat not enabled\n");
263736285Sbrian    } else if (strcmp(arg->argv[arg->argn], "no") == 0) {
263850059Sbrian      if (arg->bundle->NatEnabled) {
263937191Sbrian	PacketAliasSetMode(0, param);
264028679Sbrian	return 0;
264128679Sbrian      }
264250059Sbrian      log_Printf(LogWARN, "nat not enabled\n");
264328679Sbrian    }
264435449Sbrian  }
264528679Sbrian  return -1;
264626031Sbrian}
264750059Sbrian#endif /* #ifndef NONAT */
264831121Sbrian
264931121Sbrianstatic int
265036285SbrianLinkCommand(struct cmdargs const *arg)
265136285Sbrian{
265236285Sbrian  if (arg->argc > arg->argn+1) {
265336285Sbrian    char namelist[LINE_LEN];
265436285Sbrian    struct datalink *cx;
265536285Sbrian    char *name;
265636285Sbrian    int result = 0;
265736285Sbrian
265836285Sbrian    if (!strcmp(arg->argv[arg->argn], "*")) {
265936285Sbrian      struct datalink *dl;
266036285Sbrian
266136285Sbrian      cx = arg->bundle->links;
266236285Sbrian      while (cx) {
266336285Sbrian        /* Watch it, the command could be a ``remove'' */
266436285Sbrian        dl = cx->next;
266536285Sbrian        FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
266636285Sbrian                 arg->prompt, cx);
266736285Sbrian        for (cx = arg->bundle->links; cx; cx = cx->next)
266836285Sbrian          if (cx == dl)
266936285Sbrian            break;		/* Pointer's still valid ! */
267036285Sbrian      }
267136285Sbrian    } else {
267236285Sbrian      strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
267336285Sbrian      namelist[sizeof namelist - 1] = '\0';
267436285Sbrian      for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
267536285Sbrian        if (!bundle2datalink(arg->bundle, name)) {
267636285Sbrian          log_Printf(LogWARN, "link: %s: Invalid link name\n", name);
267736285Sbrian          return 1;
267836285Sbrian        }
267936285Sbrian
268036285Sbrian      strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
268136285Sbrian      namelist[sizeof namelist - 1] = '\0';
268236285Sbrian      for(name = strtok(namelist, ", "); name; name = strtok(NULL,", ")) {
268336285Sbrian        cx = bundle2datalink(arg->bundle, name);
268436285Sbrian        if (cx)
268536285Sbrian          FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
268636285Sbrian                   arg->prompt, cx);
268736285Sbrian        else {
268836285Sbrian          log_Printf(LogWARN, "link: %s: Invalidated link name !\n", name);
268936285Sbrian          result++;
269036285Sbrian        }
269136285Sbrian      }
269236285Sbrian    }
269336285Sbrian    return result;
269436285Sbrian  }
269536285Sbrian
269695258Sdes  log_Printf(LogWARN, "usage: %s\n", arg->cmd->syntax);
269736285Sbrian  return 2;
269836285Sbrian}
269936285Sbrian
270036285Sbrianstruct link *
270136285Sbriancommand_ChooseLink(struct cmdargs const *arg)
270236285Sbrian{
270336285Sbrian  if (arg->cx)
270436285Sbrian    return &arg->cx->physical->link;
270537210Sbrian  else if (!arg->bundle->ncp.mp.cfg.mrru) {
270636285Sbrian    struct datalink *dl = bundle2datalink(arg->bundle, NULL);
270737210Sbrian    if (dl)
270837210Sbrian      return &dl->physical->link;
270936285Sbrian  }
271037210Sbrian  return &arg->bundle->ncp.mp.link;
271136285Sbrian}
271236285Sbrian
271336285Sbrianstatic const char *
271436285Sbrianident_cmd(const char *cmd, unsigned *keep, unsigned *add)
271536285Sbrian{
271636285Sbrian  const char *result;
271736285Sbrian
271836285Sbrian  switch (*cmd) {
271936285Sbrian    case 'A':
272036285Sbrian    case 'a':
272136285Sbrian      result = "accept";
272236285Sbrian      *keep = NEG_MYMASK;
272336285Sbrian      *add = NEG_ACCEPTED;
272436285Sbrian      break;
272536285Sbrian    case 'D':
272636285Sbrian    case 'd':
272736285Sbrian      switch (cmd[1]) {
272836285Sbrian        case 'E':
272936285Sbrian        case 'e':
273036285Sbrian          result = "deny";
273136285Sbrian          *keep = NEG_MYMASK;
273236285Sbrian          *add = 0;
273336285Sbrian          break;
273436285Sbrian        case 'I':
273536285Sbrian        case 'i':
273636285Sbrian          result = "disable";
273736285Sbrian          *keep = NEG_HISMASK;
273836285Sbrian          *add = 0;
273936285Sbrian          break;
274036285Sbrian        default:
274136285Sbrian          return NULL;
274236285Sbrian      }
274336285Sbrian      break;
274436285Sbrian    case 'E':
274536285Sbrian    case 'e':
274636285Sbrian      result = "enable";
274736285Sbrian      *keep = NEG_HISMASK;
274836285Sbrian      *add = NEG_ENABLED;
274936285Sbrian      break;
275036285Sbrian    default:
275136285Sbrian      return NULL;
275236285Sbrian  }
275336285Sbrian
275436285Sbrian  return result;
275536285Sbrian}
275636285Sbrian
275736285Sbrianstatic int
275836285SbrianOptSet(struct cmdargs const *arg)
275936285Sbrian{
276037574Sbrian  int bit = (int)(long)arg->cmd->args;
276136285Sbrian  unsigned keep;			/* Keep these bits */
276236285Sbrian  unsigned add;				/* Add these bits */
276336285Sbrian
276481697Sbrian  if (ident_cmd(arg->argv[arg->argn - 2], &keep, &add) == NULL)
276536285Sbrian    return 1;
276636285Sbrian
276781885Sbrian#ifndef NOINET6
276881697Sbrian  if (add == NEG_ENABLED && bit == OPT_IPV6CP && !probe.ipv6_available) {
276981697Sbrian    log_Printf(LogWARN, "IPv6 is not available on this machine\n");
277081697Sbrian    return 1;
277181697Sbrian  }
277281885Sbrian#endif
277381697Sbrian
277436285Sbrian  if (add)
277536285Sbrian    arg->bundle->cfg.opt |= bit;
277636285Sbrian  else
277736285Sbrian    arg->bundle->cfg.opt &= ~bit;
277881697Sbrian
277936285Sbrian  return 0;
278036285Sbrian}
278136285Sbrian
278236285Sbrianstatic int
278340561SbrianIfaceAliasOptSet(struct cmdargs const *arg)
278440561Sbrian{
278540561Sbrian  unsigned save = arg->bundle->cfg.opt;
278640561Sbrian  int result = OptSet(arg);
278740561Sbrian
278840561Sbrian  if (result == 0)
278950059Sbrian    if (Enabled(arg->bundle, OPT_IFACEALIAS) && !arg->bundle->NatEnabled) {
279040561Sbrian      arg->bundle->cfg.opt = save;
279150059Sbrian      log_Printf(LogWARN, "Cannot enable iface-alias without NAT\n");
279240561Sbrian      result = 2;
279340561Sbrian    }
279440561Sbrian
279540561Sbrian  return result;
279640561Sbrian}
279740561Sbrian
279840561Sbrianstatic int
279936285SbrianNegotiateSet(struct cmdargs const *arg)
280036285Sbrian{
280137210Sbrian  long param = (long)arg->cmd->args;
280236285Sbrian  struct link *l = command_ChooseLink(arg);	/* LOCAL_CX_OPT uses this */
280336285Sbrian  struct datalink *cx = arg->cx;	/* LOCAL_CX uses this */
280436285Sbrian  const char *cmd;
280536285Sbrian  unsigned keep;			/* Keep these bits */
280636285Sbrian  unsigned add;				/* Add these bits */
280736285Sbrian
280836285Sbrian  if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL)
280936285Sbrian    return 1;
281036285Sbrian
281136285Sbrian  if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
281236285Sbrian    log_Printf(LogWARN, "%s %s: No context (use the `link' command)\n",
281336285Sbrian              cmd, arg->cmd->name);
281436285Sbrian    return 2;
281536285Sbrian  } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
281636285Sbrian    log_Printf(LogWARN, "%s %s: Redundant context (%s) ignored\n",
281736285Sbrian              cmd, arg->cmd->name, cx->name);
281836285Sbrian    cx = NULL;
281936285Sbrian  }
282036285Sbrian
282136285Sbrian  switch (param) {
282236285Sbrian    case NEG_ACFCOMP:
282336285Sbrian      cx->physical->link.lcp.cfg.acfcomp &= keep;
282436285Sbrian      cx->physical->link.lcp.cfg.acfcomp |= add;
282536285Sbrian      break;
282644106Sbrian    case NEG_CHAP05:
282744106Sbrian      cx->physical->link.lcp.cfg.chap05 &= keep;
282844106Sbrian      cx->physical->link.lcp.cfg.chap05 |= add;
282936285Sbrian      break;
283093418Sbrian#ifndef NODES
283144106Sbrian    case NEG_CHAP80:
283244106Sbrian      cx->physical->link.lcp.cfg.chap80nt &= keep;
283344106Sbrian      cx->physical->link.lcp.cfg.chap80nt |= add;
283444106Sbrian      break;
283544106Sbrian    case NEG_CHAP80LM:
283644106Sbrian      cx->physical->link.lcp.cfg.chap80lm &= keep;
283744106Sbrian      cx->physical->link.lcp.cfg.chap80lm |= add;
283844106Sbrian      break;
283967910Sbrian    case NEG_CHAP81:
284067910Sbrian      cx->physical->link.lcp.cfg.chap81 &= keep;
284167910Sbrian      cx->physical->link.lcp.cfg.chap81 |= add;
284267910Sbrian      break;
284367910Sbrian    case NEG_MPPE:
284467910Sbrian      l->ccp.cfg.neg[CCP_NEG_MPPE] &= keep;
284567910Sbrian      l->ccp.cfg.neg[CCP_NEG_MPPE] |= add;
284667910Sbrian      break;
284744106Sbrian#endif
284836285Sbrian    case NEG_DEFLATE:
284936285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE] &= keep;
285036285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE] |= add;
285136285Sbrian      break;
285236285Sbrian    case NEG_DNS:
285336285Sbrian      arg->bundle->ncp.ipcp.cfg.ns.dns_neg &= keep;
285436285Sbrian      arg->bundle->ncp.ipcp.cfg.ns.dns_neg |= add;
285536285Sbrian      break;
285647858Sbrian    case NEG_ENDDISC:
285747858Sbrian      arg->bundle->ncp.mp.cfg.negenddisc &= keep;
285847858Sbrian      arg->bundle->ncp.mp.cfg.negenddisc |= add;
285947858Sbrian      break;
286036285Sbrian    case NEG_LQR:
286136285Sbrian      cx->physical->link.lcp.cfg.lqr &= keep;
286236285Sbrian      cx->physical->link.lcp.cfg.lqr |= add;
286336285Sbrian      break;
286436285Sbrian    case NEG_PAP:
286536285Sbrian      cx->physical->link.lcp.cfg.pap &= keep;
286636285Sbrian      cx->physical->link.lcp.cfg.pap |= add;
286736285Sbrian      break;
286836285Sbrian    case NEG_PPPDDEFLATE:
286936285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE24] &= keep;
287036285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE24] |= add;
287136285Sbrian      break;
287236285Sbrian    case NEG_PRED1:
287336285Sbrian      l->ccp.cfg.neg[CCP_NEG_PRED1] &= keep;
287436285Sbrian      l->ccp.cfg.neg[CCP_NEG_PRED1] |= add;
287536285Sbrian      break;
287636285Sbrian    case NEG_PROTOCOMP:
287736285Sbrian      cx->physical->link.lcp.cfg.protocomp &= keep;
287836285Sbrian      cx->physical->link.lcp.cfg.protocomp |= add;
287936285Sbrian      break;
288036285Sbrian    case NEG_SHORTSEQ:
288140622Sbrian      switch (bundle_Phase(arg->bundle)) {
288240622Sbrian        case PHASE_DEAD:
288340622Sbrian          break;
288440622Sbrian        case PHASE_ESTABLISH:
288540622Sbrian          /* Make sure none of our links are DATALINK_LCP or greater */
288640622Sbrian          if (bundle_HighestState(arg->bundle) >= DATALINK_LCP) {
288740622Sbrian            log_Printf(LogWARN, "shortseq: Only changable before"
288840622Sbrian                       " LCP negotiations\n");
288940622Sbrian            return 1;
289040622Sbrian          }
289140622Sbrian          break;
289240622Sbrian        default:
289340622Sbrian          log_Printf(LogWARN, "shortseq: Only changable at phase"
289440622Sbrian                     " DEAD/ESTABLISH\n");
289540622Sbrian          return 1;
289636285Sbrian      }
289740622Sbrian      arg->bundle->ncp.mp.cfg.shortseq &= keep;
289840622Sbrian      arg->bundle->ncp.mp.cfg.shortseq |= add;
289936285Sbrian      break;
290036285Sbrian    case NEG_VJCOMP:
290136285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.neg &= keep;
290236285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.neg |= add;
290336285Sbrian      break;
290436285Sbrian  }
290536285Sbrian
290636285Sbrian  return 0;
290736285Sbrian}
290836285Sbrian
290936285Sbrianstatic struct cmdtab const NegotiateCommands[] = {
291062778Sbrian  {"filter-decapsulation", NULL, OptSet, LOCAL_AUTH,
291162778Sbrian  "filter on PPPoUDP payloads", "disable|enable",
291262778Sbrian  (const void *)OPT_FILTERDECAP},
2913112659Sbrian  {"force-scripts", NULL, OptSet, LOCAL_AUTH,
2914112659Sbrian   "Force execution of the configured chat scripts", "disable|enable",
2915112659Sbrian   (const void *)OPT_FORCE_SCRIPTS},
291636285Sbrian  {"idcheck", NULL, OptSet, LOCAL_AUTH, "Check FSM reply ids",
291736285Sbrian  "disable|enable", (const void *)OPT_IDCHECK},
291840666Sbrian  {"iface-alias", NULL, IfaceAliasOptSet, LOCAL_AUTH,
291962778Sbrian  "retain interface addresses", "disable|enable",
292062778Sbrian  (const void *)OPT_IFACEALIAS},
292181634Sbrian#ifndef NOINET6
292281634Sbrian  {"ipcp", NULL, OptSet, LOCAL_AUTH, "IP Network Control Protocol",
292381634Sbrian  "disable|enable", (const void *)OPT_IPCP},
292481634Sbrian  {"ipv6cp", NULL, OptSet, LOCAL_AUTH, "IPv6 Network Control Protocol",
292581634Sbrian  "disable|enable", (const void *)OPT_IPV6CP},
292681634Sbrian#endif
292747689Sbrian  {"keep-session", NULL, OptSet, LOCAL_AUTH, "Retain device session leader",
292847689Sbrian  "disable|enable", (const void *)OPT_KEEPSESSION},
292936285Sbrian  {"loopback", NULL, OptSet, LOCAL_AUTH, "Loop packets for local iface",
293036285Sbrian  "disable|enable", (const void *)OPT_LOOPBACK},
293136285Sbrian  {"passwdauth", NULL, OptSet, LOCAL_AUTH, "Use passwd file",
293236285Sbrian  "disable|enable", (const void *)OPT_PASSWDAUTH},
293340665Sbrian  {"proxy", NULL, OptSet, LOCAL_AUTH, "Create a proxy ARP entry",
293436285Sbrian  "disable|enable", (const void *)OPT_PROXY},
293540665Sbrian  {"proxyall", NULL, OptSet, LOCAL_AUTH, "Proxy ARP for all remote hosts",
293640665Sbrian  "disable|enable", (const void *)OPT_PROXYALL},
293736285Sbrian  {"sroutes", NULL, OptSet, LOCAL_AUTH, "Use sticky routes",
293836285Sbrian  "disable|enable", (const void *)OPT_SROUTES},
293969303Sbrian  {"tcpmssfixup", "mssfixup", OptSet, LOCAL_AUTH, "Modify MSS options",
294069303Sbrian  "disable|enable", (const void *)OPT_TCPMSSFIXUP},
294136285Sbrian  {"throughput", NULL, OptSet, LOCAL_AUTH, "Rolling throughput",
294236285Sbrian  "disable|enable", (const void *)OPT_THROUGHPUT},
294336285Sbrian  {"utmp", NULL, OptSet, LOCAL_AUTH, "Log connections in utmp",
294436285Sbrian  "disable|enable", (const void *)OPT_UTMP},
294536285Sbrian
294681634Sbrian#ifndef NOINET6
2947112659Sbrian#define OPT_MAX 14	/* accept/deny allowed below and not above */
294881634Sbrian#else
2949112659Sbrian#define OPT_MAX 12
295081634Sbrian#endif
295136285Sbrian
295236285Sbrian  {"acfcomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
295336285Sbrian  "Address & Control field compression", "accept|deny|disable|enable",
295436285Sbrian  (const void *)NEG_ACFCOMP},
295544106Sbrian  {"chap", "chap05", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
295636285Sbrian  "Challenge Handshake Authentication Protocol", "accept|deny|disable|enable",
295744106Sbrian  (const void *)NEG_CHAP05},
295893418Sbrian#ifndef NODES
295944106Sbrian  {"mschap", "chap80nt", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
296044106Sbrian  "Microsoft (NT) CHAP", "accept|deny|disable|enable",
296144106Sbrian  (const void *)NEG_CHAP80},
296244106Sbrian  {"LANMan", "chap80lm", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
296344106Sbrian  "Microsoft (NT) CHAP", "accept|deny|disable|enable",
296444106Sbrian  (const void *)NEG_CHAP80LM},
296567910Sbrian  {"mschapv2", "chap81", NegotiateSet, LOCAL_AUTH | LOCAL_CX,
296667910Sbrian  "Microsoft CHAP v2", "accept|deny|disable|enable",
296767910Sbrian  (const void *)NEG_CHAP81},
296867910Sbrian  {"mppe", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
296967910Sbrian  "MPPE encryption", "accept|deny|disable|enable",
297067910Sbrian  (const void *)NEG_MPPE},
297144106Sbrian#endif
297236285Sbrian  {"deflate", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
297336285Sbrian  "Deflate compression", "accept|deny|disable|enable",
297436285Sbrian  (const void *)NEG_DEFLATE},
297536285Sbrian  {"deflate24", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
297636285Sbrian  "Deflate (type 24) compression", "accept|deny|disable|enable",
297736285Sbrian  (const void *)NEG_PPPDDEFLATE},
297836285Sbrian  {"dns", NULL, NegotiateSet, LOCAL_AUTH,
297936285Sbrian  "DNS specification", "accept|deny|disable|enable", (const void *)NEG_DNS},
298047858Sbrian  {"enddisc", NULL, NegotiateSet, LOCAL_AUTH, "ENDDISC negotiation",
298147858Sbrian  "accept|deny|disable|enable", (const void *)NEG_ENDDISC},
298236285Sbrian  {"lqr", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
298336285Sbrian  "Link Quality Reports", "accept|deny|disable|enable",
298436285Sbrian  (const void *)NEG_LQR},
298536285Sbrian  {"pap", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
298636285Sbrian  "Password Authentication protocol", "accept|deny|disable|enable",
298736285Sbrian  (const void *)NEG_PAP},
298836285Sbrian  {"pred1", "predictor1", NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
298936285Sbrian  "Predictor 1 compression", "accept|deny|disable|enable",
299036285Sbrian  (const void *)NEG_PRED1},
299136285Sbrian  {"protocomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
299236285Sbrian  "Protocol field compression", "accept|deny|disable|enable",
299336285Sbrian  (const void *)NEG_PROTOCOMP},
299436285Sbrian  {"shortseq", NULL, NegotiateSet, LOCAL_AUTH,
299536285Sbrian  "MP Short Sequence Numbers", "accept|deny|disable|enable",
299636285Sbrian  (const void *)NEG_SHORTSEQ},
299736285Sbrian  {"vjcomp", NULL, NegotiateSet, LOCAL_AUTH,
299836285Sbrian  "Van Jacobson header compression", "accept|deny|disable|enable",
299936285Sbrian  (const void *)NEG_VJCOMP},
300036285Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
300136285Sbrian  "Display this message", "accept|deny|disable|enable help|? [value]",
300236285Sbrian  NegotiateCommands},
3003134789Sbrian  {NULL, NULL, NULL, 0, NULL, NULL, NULL},
300436285Sbrian};
300536285Sbrian
300636285Sbrianstatic int
300736285SbrianNegotiateCommand(struct cmdargs const *arg)
300836285Sbrian{
300936285Sbrian  if (arg->argc > arg->argn) {
301036285Sbrian    char const *argv[3];
301136285Sbrian    unsigned keep, add;
301236285Sbrian    int n;
301336285Sbrian
301436285Sbrian    if ((argv[0] = ident_cmd(arg->argv[arg->argn-1], &keep, &add)) == NULL)
301536285Sbrian      return -1;
301636285Sbrian    argv[2] = NULL;
301736285Sbrian
301836285Sbrian    for (n = arg->argn; n < arg->argc; n++) {
301936285Sbrian      argv[1] = arg->argv[n];
302036285Sbrian      FindExec(arg->bundle, NegotiateCommands + (keep == NEG_HISMASK ?
302136285Sbrian               0 : OPT_MAX), 2, 1, argv, arg->prompt, arg->cx);
302236285Sbrian    }
302336285Sbrian  } else if (arg->prompt)
302436285Sbrian    prompt_Printf(arg->prompt, "Use `%s ?' to get a list.\n",
302536285Sbrian	    arg->argv[arg->argn-1]);
302636285Sbrian  else
302736285Sbrian    log_Printf(LogWARN, "%s command must have arguments\n",
302836285Sbrian              arg->argv[arg->argn] );
302936285Sbrian
303036285Sbrian  return 0;
303136285Sbrian}
303236285Sbrian
303336285Sbrianconst char *
303436285Sbriancommand_ShowNegval(unsigned val)
303536285Sbrian{
303636285Sbrian  switch (val&3) {
303736285Sbrian    case 1: return "disabled & accepted";
303836285Sbrian    case 2: return "enabled & denied";
303936285Sbrian    case 3: return "enabled & accepted";
304036285Sbrian  }
304136285Sbrian  return "disabled & denied";
304236285Sbrian}
304336934Sbrian
304436934Sbrianstatic int
304536934SbrianClearCommand(struct cmdargs const *arg)
304636934Sbrian{
304736934Sbrian  struct pppThroughput *t;
304836934Sbrian  struct datalink *cx;
304936934Sbrian  int i, clear_type;
305036934Sbrian
305136934Sbrian  if (arg->argc < arg->argn + 1)
305236934Sbrian    return -1;
305336934Sbrian
305446686Sbrian  if (strcasecmp(arg->argv[arg->argn], "physical") == 0) {
305536934Sbrian    cx = arg->cx;
305636934Sbrian    if (!cx)
305736934Sbrian      cx = bundle2datalink(arg->bundle, NULL);
305836934Sbrian    if (!cx) {
305946686Sbrian      log_Printf(LogWARN, "A link must be specified for ``clear physical''\n");
306036934Sbrian      return 1;
306136934Sbrian    }
306264652Sbrian    t = &cx->physical->link.stats.total;
306336934Sbrian  } else if (strcasecmp(arg->argv[arg->argn], "ipcp") == 0)
306436934Sbrian    t = &arg->bundle->ncp.ipcp.throughput;
306581634Sbrian#ifndef NOINET6
306681897Sbrian  else if (strcasecmp(arg->argv[arg->argn], "ipv6cp") == 0)
306781634Sbrian    t = &arg->bundle->ncp.ipv6cp.throughput;
306881634Sbrian#endif
306936934Sbrian  else
307036934Sbrian    return -1;
307136934Sbrian
307236934Sbrian  if (arg->argc > arg->argn + 1) {
307336934Sbrian    clear_type = 0;
307436934Sbrian    for (i = arg->argn + 1; i < arg->argc; i++)
307536934Sbrian      if (strcasecmp(arg->argv[i], "overall") == 0)
307636934Sbrian        clear_type |= THROUGHPUT_OVERALL;
307736934Sbrian      else if (strcasecmp(arg->argv[i], "current") == 0)
307836934Sbrian        clear_type |= THROUGHPUT_CURRENT;
307936934Sbrian      else if (strcasecmp(arg->argv[i], "peak") == 0)
308036934Sbrian        clear_type |= THROUGHPUT_PEAK;
308136934Sbrian      else
308236934Sbrian        return -1;
308398243Sbrian  } else
308436934Sbrian    clear_type = THROUGHPUT_ALL;
308536934Sbrian
308636934Sbrian  throughput_clear(t, clear_type, arg->prompt);
308736934Sbrian  return 0;
308836934Sbrian}
308940561Sbrian
309040561Sbrianstatic int
309140561SbrianRunListCommand(struct cmdargs const *arg)
309240561Sbrian{
309340561Sbrian  const char *cmd = arg->argc ? arg->argv[arg->argc - 1] : "???";
309440561Sbrian
309564801Sbrian#ifndef NONAT
309664801Sbrian  if (arg->cmd->args == NatCommands &&
309764801Sbrian      tolower(*arg->argv[arg->argn - 1]) == 'a') {
309864801Sbrian    if (arg->prompt)
309965550Sbrian      prompt_Printf(arg->prompt, "The alias command is deprecated\n");
310064801Sbrian    else
310165550Sbrian      log_Printf(LogWARN, "The alias command is deprecated\n");
310264801Sbrian  }
310364801Sbrian#endif
310464801Sbrian
310540561Sbrian  if (arg->argc > arg->argn)
310640561Sbrian    FindExec(arg->bundle, arg->cmd->args, arg->argc, arg->argn, arg->argv,
310740561Sbrian             arg->prompt, arg->cx);
310840561Sbrian  else if (arg->prompt)
310940561Sbrian    prompt_Printf(arg->prompt, "Use `%s help' to get a list or `%s help"
311040561Sbrian                  " <option>' for syntax help.\n", cmd, cmd);
311140561Sbrian  else
311240561Sbrian    log_Printf(LogWARN, "%s command must have arguments\n", cmd);
311340561Sbrian
311440561Sbrian  return 0;
311540561Sbrian}
311640561Sbrian
311740561Sbrianstatic int
311840561SbrianIfaceAddCommand(struct cmdargs const *arg)
311940561Sbrian{
312081634Sbrian  struct ncpaddr peer, addr;
312181634Sbrian  struct ncprange ifa;
312281634Sbrian  struct in_addr mask;
312381634Sbrian  int n, how;
312440561Sbrian
312540664Sbrian  if (arg->argc == arg->argn + 1) {
312681634Sbrian    if (!ncprange_aton(&ifa, NULL, arg->argv[arg->argn]))
312740561Sbrian      return -1;
312881634Sbrian    ncpaddr_init(&peer);
312940664Sbrian  } else {
313040664Sbrian    if (arg->argc == arg->argn + 2) {
313181634Sbrian      if (!ncprange_aton(&ifa, NULL, arg->argv[arg->argn]))
313240664Sbrian        return -1;
313340664Sbrian      n = 1;
313440664Sbrian    } else if (arg->argc == arg->argn + 3) {
313581634Sbrian      if (!ncpaddr_aton(&addr, NULL, arg->argv[arg->argn]))
313640664Sbrian        return -1;
313781634Sbrian      if (ncpaddr_family(&addr) != AF_INET)
313840664Sbrian        return -1;
313981634Sbrian      ncprange_sethost(&ifa, &addr);
314081634Sbrian      if (!ncpaddr_aton(&addr, NULL, arg->argv[arg->argn + 1]))
314181634Sbrian        return -1;
314281634Sbrian      if (!ncpaddr_getip4(&addr, &mask))
314381634Sbrian        return -1;
314481634Sbrian      if (!ncprange_setip4mask(&ifa, mask))
314581634Sbrian        return -1;
314640664Sbrian      n = 2;
314740664Sbrian    } else
314840561Sbrian      return -1;
314940561Sbrian
315081634Sbrian    if (!ncpaddr_aton(&peer, NULL, arg->argv[arg->argn + n]))
315140664Sbrian      return -1;
315281634Sbrian
315381634Sbrian    if (ncprange_family(&ifa) != ncpaddr_family(&peer)) {
315481634Sbrian      log_Printf(LogWARN, "IfaceAddCommand: src and dst address families"
315581634Sbrian                 " differ\n");
315681634Sbrian      return -1;
315781634Sbrian    }
315840664Sbrian  }
315940561Sbrian
316040561Sbrian  how = IFACE_ADD_LAST;
316140561Sbrian  if (arg->cmd->args)
316240561Sbrian    how |= IFACE_FORCE_ADD;
316340561Sbrian
316481634Sbrian  return !iface_Add(arg->bundle->iface, &arg->bundle->ncp, &ifa, &peer, how);
316540561Sbrian}
316640561Sbrian
316740561Sbrianstatic int
316840561SbrianIfaceDeleteCommand(struct cmdargs const *arg)
316940561Sbrian{
317081634Sbrian  struct ncpaddr ifa;
317181634Sbrian  struct in_addr ifa4;
317240561Sbrian  int ok;
317340561Sbrian
317440561Sbrian  if (arg->argc != arg->argn + 1)
317540561Sbrian    return -1;
317640561Sbrian
317781634Sbrian  if (!ncpaddr_aton(&ifa, NULL, arg->argv[arg->argn]))
317840561Sbrian    return -1;
317940561Sbrian
318040561Sbrian  if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED &&
318181634Sbrian      ncpaddr_getip4(&ifa, &ifa4) &&
318281634Sbrian      arg->bundle->ncp.ipcp.my_ip.s_addr == ifa4.s_addr) {
318340561Sbrian    log_Printf(LogWARN, "%s: Cannot remove active interface address\n",
318481634Sbrian               ncpaddr_ntoa(&ifa));
318540561Sbrian    return 1;
318640561Sbrian  }
318740561Sbrian
318881634Sbrian  ok = iface_Delete(arg->bundle->iface, &arg->bundle->ncp, &ifa);
318940561Sbrian  if (!ok) {
319040561Sbrian    if (arg->cmd->args)
319140561Sbrian      ok = 1;
319240561Sbrian    else if (arg->prompt)
319381634Sbrian      prompt_Printf(arg->prompt, "%s: No such interface address\n",
319481634Sbrian                    ncpaddr_ntoa(&ifa));
319540561Sbrian    else
319681634Sbrian      log_Printf(LogWARN, "%s: No such interface address\n",
319781634Sbrian                 ncpaddr_ntoa(&ifa));
319840561Sbrian  }
319940561Sbrian
320040561Sbrian  return !ok;
320140561Sbrian}
320240561Sbrian
320340561Sbrianstatic int
320440561SbrianIfaceClearCommand(struct cmdargs const *arg)
320540561Sbrian{
320681634Sbrian  int family, how;
320740561Sbrian
320881634Sbrian  family = 0;
320981634Sbrian  if (arg->argc == arg->argn + 1) {
321081634Sbrian    if (strcasecmp(arg->argv[arg->argn], "inet") == 0)
321181634Sbrian      family = AF_INET;
321281634Sbrian#ifndef NOINET6
321381897Sbrian    else if (strcasecmp(arg->argv[arg->argn], "inet6") == 0)
321481634Sbrian      family = AF_INET6;
321581634Sbrian#endif
321681634Sbrian    else
321781634Sbrian      return -1;
321881634Sbrian  } else if (arg->argc != arg->argn)
321940561Sbrian    return -1;
322040561Sbrian
322140941Sbrian  how = arg->bundle->ncp.ipcp.fsm.state == ST_OPENED ||
322240941Sbrian        arg->bundle->phys_type.all & PHYS_AUTO ?
322340561Sbrian        IFACE_CLEAR_ALIASES : IFACE_CLEAR_ALL;
322481634Sbrian  iface_Clear(arg->bundle->iface, &arg->bundle->ncp, family, how);
322540561Sbrian
322640561Sbrian  return 0;
322740561Sbrian}
322840679Sbrian
322940679Sbrianstatic int
323040679SbrianSetProcTitle(struct cmdargs const *arg)
323140679Sbrian{
323240679Sbrian  static char title[LINE_LEN];
323386028Sbrian  char *argv[MAXARGS];
323486028Sbrian  int argc = arg->argc - arg->argn;
323540679Sbrian
3236134789Sbrian  if (arg->argc <= arg->argn) {
323764698Sbrian    SetTitle(NULL);
323840679Sbrian    return 0;
323940679Sbrian  }
324040679Sbrian
3241134789Sbrian  if ((unsigned)argc >= sizeof argv / sizeof argv[0]) {
324240679Sbrian    argc = sizeof argv / sizeof argv[0] - 1;
324340679Sbrian    log_Printf(LogWARN, "Truncating proc title to %d args\n", argc);
324440679Sbrian  }
324547849Sbrian  command_Expand(argv, argc, arg->argv + arg->argn, arg->bundle, 1, getpid());
324685991Sbrian  Concatinate(title, sizeof title, argc, (const char *const *)argv);
324764698Sbrian  SetTitle(title);
324885991Sbrian  command_Free(argc, argv);
324940679Sbrian
325040679Sbrian  return 0;
325140679Sbrian}
3252