command.c revision 38557
16059Samurai/*
26059Samurai *		PPP User command processing module
36059Samurai *
46059Samurai *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
56059Samurai *
66059Samurai *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
76059Samurai *
86059Samurai * Redistribution and use in source and binary forms are permitted
96059Samurai * provided that the above copyright notice and this paragraph are
106059Samurai * duplicated in all such forms and that any documentation,
116059Samurai * advertising materials, and other materials related to such
126059Samurai * distribution and use acknowledge that the software was developed
136059Samurai * by the Internet Initiative Japan, Inc.  The name of the
146059Samurai * IIJ may not be used to endorse or promote products derived
156059Samurai * from this software without specific prior written permission.
166059Samurai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
176059Samurai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
186059Samurai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
198857Srgrimes *
2038557Sbrian * $Id: command.c,v 1.160 1998/08/25 17:48:42 brian Exp $
218857Srgrimes *
226059Samurai */
2336285Sbrian#include <sys/types.h>
2430715Sbrian#include <netinet/in_systm.h>
2526031Sbrian#include <netinet/in.h>
2630715Sbrian#include <netinet/ip.h>
2726031Sbrian#include <arpa/inet.h>
2830715Sbrian#include <sys/socket.h>
2926031Sbrian#include <net/route.h>
3030715Sbrian#include <netdb.h>
3136285Sbrian#include <sys/un.h>
3230715Sbrian
3331343Sbrian#ifndef NOALIAS
3426031Sbrian#include <alias.h>
3531343Sbrian#endif
3630715Sbrian#include <errno.h>
3726516Sbrian#include <fcntl.h>
3830715Sbrian#include <paths.h>
3930715Sbrian#include <stdio.h>
4030715Sbrian#include <stdlib.h>
4130715Sbrian#include <string.h>
4230715Sbrian#include <sys/wait.h>
4330715Sbrian#include <termios.h>
4430715Sbrian#include <unistd.h>
4530715Sbrian
4637009Sbrian#include "defs.h"
4731343Sbrian#include "command.h"
4830715Sbrian#include "mbuf.h"
4930715Sbrian#include "log.h"
5030715Sbrian#include "timer.h"
516059Samurai#include "fsm.h"
526059Samurai#include "lcp.h"
5331690Sbrian#include "iplist.h"
5436285Sbrian#include "throughput.h"
5536285Sbrian#include "slcompress.h"
5638557Sbrian#include "lqr.h"
5738557Sbrian#include "hdlc.h"
586059Samurai#include "ipcp.h"
596059Samurai#include "modem.h"
6031343Sbrian#ifndef NOALIAS
6126031Sbrian#include "alias_cmd.h"
6231343Sbrian#endif
6325630Sbrian#include "systems.h"
6436285Sbrian#include "filter.h"
6536285Sbrian#include "descriptor.h"
6630715Sbrian#include "main.h"
6730715Sbrian#include "route.h"
6830715Sbrian#include "ccp.h"
6931080Sbrian#include "auth.h"
7036285Sbrian#include "async.h"
7136285Sbrian#include "link.h"
7236285Sbrian#include "physical.h"
7336285Sbrian#include "mp.h"
7436285Sbrian#include "bundle.h"
7536285Sbrian#include "server.h"
7636285Sbrian#include "prompt.h"
7736285Sbrian#include "chat.h"
7836285Sbrian#include "chap.h"
7938174Sbrian#include "cbcp.h"
8036285Sbrian#include "datalink.h"
816059Samurai
8236285Sbrian/* ``set'' values */
8336285Sbrian#define	VAR_AUTHKEY	0
8436285Sbrian#define	VAR_DIAL	1
8536285Sbrian#define	VAR_LOGIN	2
8636285Sbrian#define	VAR_AUTHNAME	3
8736285Sbrian#define	VAR_AUTOLOAD	4
8836285Sbrian#define	VAR_WINSIZE	5
8936285Sbrian#define	VAR_DEVICE	6
9036285Sbrian#define	VAR_ACCMAP	7
9136285Sbrian#define	VAR_MRRU	8
9236285Sbrian#define	VAR_MRU		9
9336285Sbrian#define	VAR_MTU		10
9436285Sbrian#define	VAR_OPENMODE	11
9536285Sbrian#define	VAR_PHONE	12
9636285Sbrian#define	VAR_HANGUP	13
9736285Sbrian#define	VAR_IDLETIMEOUT	14
9836285Sbrian#define	VAR_LQRPERIOD	15
9936285Sbrian#define	VAR_LCPRETRY	16
10036285Sbrian#define	VAR_CHAPRETRY	17
10136285Sbrian#define	VAR_PAPRETRY	18
10236285Sbrian#define	VAR_CCPRETRY	19
10336285Sbrian#define	VAR_IPCPRETRY	20
10436285Sbrian#define	VAR_DNS		21
10536285Sbrian#define	VAR_NBNS	22
10636285Sbrian#define	VAR_MODE	23
10738174Sbrian#define	VAR_CALLBACK	24
10838174Sbrian#define	VAR_CBCP	25
10938544Sbrian#define	VAR_CHOKED	26
1106059Samurai
11136285Sbrian/* ``accept|deny|disable|enable'' masks */
11236285Sbrian#define NEG_HISMASK (1)
11336285Sbrian#define NEG_MYMASK (2)
11436285Sbrian
11536285Sbrian/* ``accept|deny|disable|enable'' values */
11636285Sbrian#define NEG_ACFCOMP	40
11736285Sbrian#define NEG_CHAP	41
11836285Sbrian#define NEG_DEFLATE	42
11936285Sbrian#define NEG_LQR		43
12036285Sbrian#define NEG_PAP		44
12136285Sbrian#define NEG_PPPDDEFLATE	45
12236285Sbrian#define NEG_PRED1	46
12336285Sbrian#define NEG_PROTOCOMP	47
12436285Sbrian#define NEG_SHORTSEQ	48
12536285Sbrian#define NEG_VJCOMP	49
12636285Sbrian#define NEG_DNS		50
12736285Sbrian
12837373Sbrianconst char Version[] = "2.0";
12938557Sbrianconst char VersionDate[] = "$Date: 1998/08/25 17:48:42 $";
13036285Sbrian
13136285Sbrianstatic int ShowCommand(struct cmdargs const *);
13236285Sbrianstatic int TerminalCommand(struct cmdargs const *);
13336285Sbrianstatic int QuitCommand(struct cmdargs const *);
13436285Sbrianstatic int OpenCommand(struct cmdargs const *);
13536285Sbrianstatic int CloseCommand(struct cmdargs const *);
13636285Sbrianstatic int DownCommand(struct cmdargs const *);
13736285Sbrianstatic int AllowCommand(struct cmdargs const *);
13836285Sbrianstatic int SetCommand(struct cmdargs const *);
13936285Sbrianstatic int LinkCommand(struct cmdargs const *);
14036285Sbrianstatic int AddCommand(struct cmdargs const *);
14136285Sbrianstatic int DeleteCommand(struct cmdargs const *);
14236285Sbrianstatic int NegotiateCommand(struct cmdargs const *);
14336934Sbrianstatic int ClearCommand(struct cmdargs const *);
14431343Sbrian#ifndef NOALIAS
14536285Sbrianstatic int AliasCommand(struct cmdargs const *);
14636285Sbrianstatic int AliasEnable(struct cmdargs const *);
14736285Sbrianstatic int AliasOption(struct cmdargs const *);
14831343Sbrian#endif
1496059Samurai
15036285Sbrianstatic const char *
15136285Sbrianshowcx(struct cmdtab const *cmd)
15236285Sbrian{
15336285Sbrian  if (cmd->lauth & LOCAL_CX)
15436285Sbrian    return "(c)";
15536285Sbrian  else if (cmd->lauth & LOCAL_CX_OPT)
15636285Sbrian    return "(o)";
15736285Sbrian
15836285Sbrian  return "";
15936285Sbrian}
16036285Sbrian
1616059Samuraistatic int
16231343SbrianHelpCommand(struct cmdargs const *arg)
1636059Samurai{
16428679Sbrian  struct cmdtab const *cmd;
16536285Sbrian  int n, cmax, dmax, cols, cxlen;
16636285Sbrian  const char *cx;
1676059Samurai
16836285Sbrian  if (!arg->prompt) {
16936285Sbrian    log_Printf(LogWARN, "help: Cannot help without a prompt\n");
17026516Sbrian    return 0;
17136285Sbrian  }
17226516Sbrian
17336285Sbrian  if (arg->argc > arg->argn) {
17436285Sbrian    for (cmd = arg->cmdtab; cmd->name || cmd->alias; cmd++)
17536285Sbrian      if ((cmd->lauth & arg->prompt->auth) &&
17636285Sbrian          ((cmd->name && !strcasecmp(cmd->name, arg->argv[arg->argn])) ||
17736285Sbrian           (cmd->alias && !strcasecmp(cmd->alias, arg->argv[arg->argn])))) {
17836285Sbrian	prompt_Printf(arg->prompt, "%s %s\n", cmd->syntax, showcx(cmd));
17928679Sbrian	return 0;
1806059Samurai      }
18126516Sbrian    return -1;
1826059Samurai  }
18336285Sbrian
18431372Sbrian  cmax = dmax = 0;
18536285Sbrian  for (cmd = arg->cmdtab; cmd->func; cmd++)
18636285Sbrian    if (cmd->name && (cmd->lauth & arg->prompt->auth)) {
18736285Sbrian      if ((n = strlen(cmd->name) + strlen(showcx(cmd))) > cmax)
18831372Sbrian        cmax = n;
18931372Sbrian      if ((n = strlen(cmd->helpmes)) > dmax)
19031372Sbrian        dmax = n;
19131372Sbrian    }
19231372Sbrian
19331372Sbrian  cols = 80 / (dmax + cmax + 3);
1946059Samurai  n = 0;
19536285Sbrian  prompt_Printf(arg->prompt, "(o) = Optional context,"
19636285Sbrian                " (c) = Context required\n");
19736285Sbrian  for (cmd = arg->cmdtab; cmd->func; cmd++)
19836285Sbrian    if (cmd->name && (cmd->lauth & arg->prompt->auth)) {
19936285Sbrian      cx = showcx(cmd);
20036285Sbrian      cxlen = cmax - strlen(cmd->name);
20136285Sbrian      prompt_Printf(arg->prompt, " %s%-*.*s: %-*.*s",
20236285Sbrian              cmd->name, cxlen, cxlen, cx, dmax, dmax, cmd->helpmes);
20331372Sbrian      if (++n % cols == 0)
20436285Sbrian        prompt_Printf(arg->prompt, "\n");
2056059Samurai    }
20631372Sbrian  if (n % cols != 0)
20736285Sbrian    prompt_Printf(arg->prompt, "\n");
20826516Sbrian
20926516Sbrian  return 0;
2106059Samurai}
2116059Samurai
21236285Sbrianstatic int
21336285SbrianCloneCommand(struct cmdargs const *arg)
2146059Samurai{
21536285Sbrian  char namelist[LINE_LEN];
21636285Sbrian  char *name;
21736285Sbrian  int f;
2186059Samurai
21936285Sbrian  if (arg->argc == arg->argn)
22036285Sbrian    return -1;
22136285Sbrian
22236285Sbrian  namelist[sizeof namelist - 1] = '\0';
22336285Sbrian  for (f = arg->argn; f < arg->argc; f++) {
22436285Sbrian    strncpy(namelist, arg->argv[f], sizeof namelist - 1);
22536285Sbrian    for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
22636285Sbrian      bundle_DatalinkClone(arg->bundle, arg->cx, name);
2276059Samurai  }
22836285Sbrian
22936285Sbrian  return 0;
2306059Samurai}
2316059Samurai
2326059Samuraistatic int
23336285SbrianRemoveCommand(struct cmdargs const *arg)
2346059Samurai{
23536285Sbrian  if (arg->argc != arg->argn)
23636285Sbrian    return -1;
23711336Samurai
23836285Sbrian  if (arg->cx->state != DATALINK_CLOSED) {
23936285Sbrian    log_Printf(LogWARN, "remove: Cannot delete links that aren't closed\n");
24036285Sbrian    return 2;
2416059Samurai  }
24226516Sbrian
24336285Sbrian  bundle_DatalinkRemove(arg->bundle, arg->cx);
24436285Sbrian  return 0;
24536285Sbrian}
24632711Sbrian
24736285Sbrianstatic int
24836285SbrianRenameCommand(struct cmdargs const *arg)
24936285Sbrian{
25036285Sbrian  if (arg->argc != arg->argn + 1)
25136285Sbrian    return -1;
25231121Sbrian
25336285Sbrian  if (bundle_RenameDatalink(arg->bundle, arg->cx, arg->argv[arg->argn]))
25436285Sbrian    return 0;
25536285Sbrian
25636285Sbrian  log_Printf(LogWARN, "%s -> %s: target name already exists\n",
25736285Sbrian             arg->cx->name, arg->argv[arg->argn]);
25836285Sbrian  return 1;
25936285Sbrian}
26036285Sbrian
26136285Sbrianint
26236285SbrianLoadCommand(struct cmdargs const *arg)
26336285Sbrian{
26436285Sbrian  const char *name;
26536285Sbrian
26636285Sbrian  if (arg->argc > arg->argn)
26736285Sbrian    name = arg->argv[arg->argn];
26836285Sbrian  else
26936285Sbrian    name = "default";
27036285Sbrian
27136928Sbrian  if (!system_IsValid(name, arg->prompt, arg->bundle->phys_type.all)) {
27237019Sbrian    log_Printf(LogWARN, "%s: Label not allowed\n", name);
27336285Sbrian    return 1;
27436285Sbrian  } else {
27536285Sbrian    /*
27636285Sbrian     * Set the label before & after so that `set enddisc' works and
27736285Sbrian     * we handle nested `load' commands.
27836285Sbrian     */
27936285Sbrian    bundle_SetLabel(arg->bundle, arg->argc > arg->argn ? name : NULL);
28037008Sbrian    if (system_Select(arg->bundle, name, CONFFILE, arg->prompt, arg->cx) < 0) {
28136285Sbrian      bundle_SetLabel(arg->bundle, NULL);
28236285Sbrian      log_Printf(LogWARN, "%s: label not found.\n", name);
28336285Sbrian      return -1;
28432403Sbrian    }
28536285Sbrian    bundle_SetLabel(arg->bundle, arg->argc > arg->argn ? name : NULL);
28636285Sbrian  }
28726516Sbrian  return 0;
2886059Samurai}
2896059Samurai
29036285Sbrianint
29136285SbrianSaveCommand(struct cmdargs const *arg)
29236285Sbrian{
29336285Sbrian  log_Printf(LogWARN, "save command is not implemented (yet).\n");
29436285Sbrian  return 1;
29536285Sbrian}
29636285Sbrian
29710528Samuraistatic int
29836285SbrianDialCommand(struct cmdargs const *arg)
29928536Sbrian{
30036285Sbrian  int res;
30136285Sbrian
30236465Sbrian  if ((arg->cx && !(arg->cx->physical->type & (PHYS_INTERACTIVE|PHYS_AUTO)))
30336465Sbrian      || (!arg->cx &&
30436928Sbrian          (arg->bundle->phys_type.all & ~(PHYS_INTERACTIVE|PHYS_AUTO)))) {
30536285Sbrian    log_Printf(LogWARN, "Manual dial is only available for auto and"
30636285Sbrian              " interactive links\n");
30736285Sbrian    return 1;
30834536Sbrian  }
30936285Sbrian
31036285Sbrian  if (arg->argc > arg->argn && (res = LoadCommand(arg)) != 0)
31136285Sbrian    return res;
31236285Sbrian
31337993Sbrian  bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1);
31436285Sbrian
31536285Sbrian  return 0;
31628536Sbrian}
31728536Sbrian
31828536Sbrianstatic int
31931343SbrianShellCommand(struct cmdargs const *arg, int bg)
32010528Samurai{
32110528Samurai  const char *shell;
32210528Samurai  pid_t shpid;
32331343Sbrian  int argc;
32431343Sbrian  char *argv[MAXARGS];
32520813Sjkh
32618856Ssos#ifdef SHELL_ONLY_INTERACTIVELY
32726911Sbrian  /* we're only allowed to shell when we run ppp interactively */
32836285Sbrian  if (arg->prompt && arg->prompt->owner) {
32936285Sbrian    log_Printf(LogWARN, "Can't start a shell from a network connection\n");
33026516Sbrian    return 1;
33110528Samurai  }
33226911Sbrian#endif
33328679Sbrian
33436285Sbrian  if (arg->argc == arg->argn) {
33536285Sbrian    if (!arg->prompt) {
33636285Sbrian      log_Printf(LogWARN, "Can't start an interactive shell from"
33736285Sbrian                " a config file\n");
33828381Sbrian      return 1;
33936285Sbrian    } else if (arg->prompt->owner) {
34036285Sbrian      log_Printf(LogWARN, "Can't start an interactive shell from"
34136285Sbrian                " a socket connection\n");
34236285Sbrian      return 1;
34328381Sbrian    } else if (bg) {
34436285Sbrian      log_Printf(LogWARN, "Can only start an interactive shell in"
34528679Sbrian		" the foreground mode\n");
34628381Sbrian      return 1;
34728381Sbrian    }
34834536Sbrian  }
34934536Sbrian
35028679Sbrian  if ((shpid = fork()) == 0) {
35136285Sbrian    int i, fd;
35218531Sbde
35336285Sbrian    if ((shell = getenv("SHELL")) == 0)
35436285Sbrian      shell = _PATH_BSHELL;
35532017Sbrian
35636285Sbrian    timer_TermService();
35736285Sbrian
35836285Sbrian    if (arg->prompt)
35936285Sbrian      fd = arg->prompt->fd_out;
36036285Sbrian    else if ((fd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
36136285Sbrian      log_Printf(LogALERT, "Failed to open %s: %s\n",
36236285Sbrian                _PATH_DEVNULL, strerror(errno));
36328679Sbrian      exit(1);
36428679Sbrian    }
36528679Sbrian    for (i = 0; i < 3; i++)
36628679Sbrian      dup2(fd, i);
36726516Sbrian
36836285Sbrian    fcntl(3, F_SETFD, 1);	/* Set close-on-exec flag */
36926516Sbrian
37031061Sbrian    setuid(geteuid());
37136285Sbrian    if (arg->argc > arg->argn) {
37228679Sbrian      /* substitute pseudo args */
37336285Sbrian      argv[0] = strdup(arg->argv[arg->argn]);
37436285Sbrian      for (argc = 1; argc < arg->argc - arg->argn; argc++) {
37536285Sbrian	if (strcasecmp(arg->argv[argc + arg->argn], "HISADDR") == 0)
37636285Sbrian	  argv[argc] = strdup(inet_ntoa(arg->bundle->ncp.ipcp.peer_ip));
37736285Sbrian	else if (strcasecmp(arg->argv[argc + arg->argn], "INTERFACE") == 0)
37836285Sbrian	  argv[argc] = strdup(arg->bundle->ifp.Name);
37936285Sbrian	else if (strcasecmp(arg->argv[argc + arg->argn], "MYADDR") == 0)
38036285Sbrian	  argv[argc] = strdup(inet_ntoa(arg->bundle->ncp.ipcp.my_ip));
38131343Sbrian        else
38236285Sbrian          argv[argc] = strdup(arg->argv[argc + arg->argn]);
38331343Sbrian      }
38431343Sbrian      argv[argc] = NULL;
38528679Sbrian      if (bg) {
38628679Sbrian	pid_t p;
38710528Samurai
38828679Sbrian	p = getpid();
38928679Sbrian	if (daemon(1, 1) == -1) {
39036832Sbrian	  log_Printf(LogERROR, "%d: daemon: %s\n", (int)p, strerror(errno));
39128679Sbrian	  exit(1);
39228679Sbrian	}
39336285Sbrian      } else if (arg->prompt)
39436285Sbrian        printf("ppp: Pausing until %s finishes\n", arg->argv[arg->argn]);
39531343Sbrian      execvp(argv[0], argv);
39630316Sbrian    } else {
39736285Sbrian      if (arg->prompt)
39832017Sbrian        printf("ppp: Pausing until %s finishes\n", shell);
39936285Sbrian      prompt_TtyOldMode(arg->prompt);
40031343Sbrian      execl(shell, shell, NULL);
40130316Sbrian    }
40220813Sjkh
40336285Sbrian    log_Printf(LogWARN, "exec() of %s failed\n",
40436285Sbrian              arg->argc > arg->argn ? arg->argv[arg->argn] : shell);
40528679Sbrian    exit(255);
40610528Samurai  }
40736285Sbrian
40836285Sbrian  if (shpid == (pid_t) - 1)
40936285Sbrian    log_Printf(LogERROR, "Fork failed: %s\n", strerror(errno));
41036285Sbrian  else {
41110528Samurai    int status;
41231343Sbrian    waitpid(shpid, &status, 0);
41310528Samurai  }
41420813Sjkh
41536285Sbrian  if (arg->prompt && !arg->prompt->owner)
41636285Sbrian    prompt_TtyCommandMode(arg->prompt);
41720813Sjkh
41836285Sbrian  return 0;
41910528Samurai}
42010528Samurai
42131343Sbrianstatic int
42231343SbrianBgShellCommand(struct cmdargs const *arg)
42331343Sbrian{
42436285Sbrian  if (arg->argc == arg->argn)
42531343Sbrian    return -1;
42631343Sbrian  return ShellCommand(arg, 1);
42731343Sbrian}
42831343Sbrian
42931343Sbrianstatic int
43031343SbrianFgShellCommand(struct cmdargs const *arg)
43131343Sbrian{
43231343Sbrian  return ShellCommand(arg, 0);
43331343Sbrian}
43431343Sbrian
43530715Sbrianstatic struct cmdtab const Commands[] = {
43636285Sbrian  {"accept", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
43728679Sbrian  "accept option request", "accept option .."},
43828679Sbrian  {"add", NULL, AddCommand, LOCAL_AUTH,
43932109Sbrian  "add route", "add dest mask gateway", NULL},
44036285Sbrian  {NULL, "add!", AddCommand, LOCAL_AUTH,
44132109Sbrian  "add or change route", "add! dest mask gateway", (void *)1},
44236285Sbrian#ifndef NOALIAS
44336285Sbrian  {"alias", NULL, AliasCommand, LOCAL_AUTH,
44436285Sbrian  "alias control", "alias option [yes|no]"},
44536285Sbrian#endif
44631121Sbrian  {"allow", "auth", AllowCommand, LOCAL_AUTH,
44731121Sbrian  "Allow ppp access", "allow users|modes ...."},
44828679Sbrian  {"bg", "!bg", BgShellCommand, LOCAL_AUTH,
44931372Sbrian  "Run a background command", "[!]bg command"},
45036934Sbrian  {"clear", NULL, ClearCommand, LOCAL_AUTH | LOCAL_CX_OPT,
45136934Sbrian  "Clear throughput statistics", "clear ipcp|modem [current|overall|peak]..."},
45236285Sbrian  {"clone", NULL, CloneCommand, LOCAL_AUTH | LOCAL_CX,
45336285Sbrian  "Clone a link", "clone newname..."},
45436285Sbrian  {"close", NULL, CloseCommand, LOCAL_AUTH | LOCAL_CX_OPT,
45536285Sbrian  "Close an FSM", "close [lcp|ccp]"},
45628679Sbrian  {"delete", NULL, DeleteCommand, LOCAL_AUTH,
45732109Sbrian  "delete route", "delete dest", NULL},
45836285Sbrian  {NULL, "delete!", DeleteCommand, LOCAL_AUTH,
45932109Sbrian  "delete a route if it exists", "delete! dest", (void *)1},
46036285Sbrian  {"deny", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
46128679Sbrian  "Deny option request", "deny option .."},
46236285Sbrian  {"dial", "call", DialCommand, LOCAL_AUTH | LOCAL_CX_OPT,
46337955Sbrian  "Dial and login", "dial|call [remote]", NULL},
46436285Sbrian  {"disable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
46528679Sbrian  "Disable option", "disable option .."},
46636285Sbrian  {"down", NULL, DownCommand, LOCAL_AUTH | LOCAL_CX_OPT,
46736285Sbrian  "Generate a down event", "down"},
46836285Sbrian  {"enable", NULL, NegotiateCommand, LOCAL_AUTH | LOCAL_CX_OPT,
46928679Sbrian  "Enable option", "enable option .."},
47036285Sbrian  {"link", "datalink", LinkCommand, LOCAL_AUTH,
47136285Sbrian  "Link specific commands", "link name command ..."},
47237008Sbrian  {"load", NULL, LoadCommand, LOCAL_AUTH | LOCAL_CX_OPT,
47328679Sbrian  "Load settings", "load [remote]"},
47436285Sbrian  {"open", NULL, OpenCommand, LOCAL_AUTH | LOCAL_CX_OPT,
47537955Sbrian  "Open an FSM", "open! [lcp|ccp|ipcp]", (void *)1},
47636285Sbrian  {"passwd", NULL, PasswdCommand, LOCAL_NO_AUTH,
47736285Sbrian  "Password for manipulation", "passwd LocalPassword"},
47836285Sbrian  {"quit", "bye", QuitCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
47936285Sbrian  "Quit PPP program", "quit|bye [all]"},
48036285Sbrian  {"remove", "rm", RemoveCommand, LOCAL_AUTH | LOCAL_CX,
48136285Sbrian  "Remove a link", "remove"},
48236285Sbrian  {"rename", "mv", RenameCommand, LOCAL_AUTH | LOCAL_CX,
48336285Sbrian  "Rename a link", "rename name"},
48428679Sbrian  {"save", NULL, SaveCommand, LOCAL_AUTH,
48528679Sbrian  "Save settings", "save"},
48636285Sbrian  {"set", "setup", SetCommand, LOCAL_AUTH | LOCAL_CX_OPT,
48728679Sbrian  "Set parameters", "set[up] var value"},
48828679Sbrian  {"shell", "!", FgShellCommand, LOCAL_AUTH,
48928679Sbrian  "Run a subshell", "shell|! [sh command]"},
49036285Sbrian  {"show", NULL, ShowCommand, LOCAL_AUTH | LOCAL_CX_OPT,
49131372Sbrian  "Show status and stats", "show var"},
49236285Sbrian  {"term", NULL, TerminalCommand, LOCAL_AUTH | LOCAL_CX,
49331372Sbrian  "Enter terminal mode", "term"},
49428679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
49531343Sbrian  "Display this message", "help|? [command]", Commands},
49628679Sbrian  {NULL, NULL, NULL},
4976059Samurai};
4986059Samurai
49928536Sbrianstatic int
50031343SbrianShowEscape(struct cmdargs const *arg)
5016059Samurai{
50236285Sbrian  if (arg->cx->physical->async.cfg.EscMap[32]) {
50336285Sbrian    int code, bit;
50436285Sbrian    const char *sep = "";
5056059Samurai
50626516Sbrian    for (code = 0; code < 32; code++)
50736285Sbrian      if (arg->cx->physical->async.cfg.EscMap[code])
50828679Sbrian	for (bit = 0; bit < 8; bit++)
50936285Sbrian	  if (arg->cx->physical->async.cfg.EscMap[code] & (1 << bit)) {
51036285Sbrian	    prompt_Printf(arg->prompt, "%s0x%02x", sep, (code << 3) + bit);
51136285Sbrian            sep = ", ";
51236285Sbrian          }
51336285Sbrian    prompt_Printf(arg->prompt, "\n");
5146059Samurai  }
51531077Sbrian  return 0;
5166059Samurai}
5176059Samurai
51828679Sbrianstatic int
51936285SbrianShowTimerList(struct cmdargs const *arg)
5206059Samurai{
52136285Sbrian  timer_Show(0, arg->prompt);
52231077Sbrian  return 0;
5236059Samurai}
5246059Samurai
52528679Sbrianstatic int
52631343SbrianShowStopped(struct cmdargs const *arg)
52728327Sbrian{
52836285Sbrian  prompt_Printf(arg->prompt, " Stopped Timer:  LCP: ");
52936285Sbrian  if (!arg->cx->physical->link.lcp.fsm.StoppedTimer.load)
53036285Sbrian    prompt_Printf(arg->prompt, "Disabled");
53128327Sbrian  else
53236285Sbrian    prompt_Printf(arg->prompt, "%ld secs",
53336285Sbrian                  arg->cx->physical->link.lcp.fsm.StoppedTimer.load / SECTICKS);
53428461Sbrian
53536285Sbrian  prompt_Printf(arg->prompt, ", CCP: ");
53636285Sbrian  if (!arg->cx->physical->link.ccp.fsm.StoppedTimer.load)
53736285Sbrian    prompt_Printf(arg->prompt, "Disabled");
53828461Sbrian  else
53936285Sbrian    prompt_Printf(arg->prompt, "%ld secs",
54036285Sbrian                  arg->cx->physical->link.ccp.fsm.StoppedTimer.load / SECTICKS);
54128461Sbrian
54236285Sbrian  prompt_Printf(arg->prompt, "\n");
54328461Sbrian
54431077Sbrian  return 0;
54528327Sbrian}
54628327Sbrian
54728679Sbrianstatic int
54831343SbrianShowVersion(struct cmdargs const *arg)
5496059Samurai{
55036285Sbrian  prompt_Printf(arg->prompt, "PPP Version %s - %s\n", Version, VersionDate);
55131077Sbrian  return 0;
5526059Samurai}
5536059Samurai
55428679Sbrianstatic int
55536285SbrianShowProtocolStats(struct cmdargs const *arg)
55626326Sbrian{
55736285Sbrian  struct link *l = command_ChooseLink(arg);
55826326Sbrian
55936285Sbrian  prompt_Printf(arg->prompt, "%s:\n", l->name);
56036285Sbrian  link_ReportProtocolStatus(l, arg->prompt);
56131077Sbrian  return 0;
56226326Sbrian}
56326326Sbrian
56430715Sbrianstatic struct cmdtab const ShowCommands[] = {
56536285Sbrian  {"bundle", NULL, bundle_ShowStatus, LOCAL_AUTH,
56636285Sbrian  "bundle details", "show bundle"},
56736285Sbrian  {"ccp", NULL, ccp_ReportStatus, LOCAL_AUTH | LOCAL_CX_OPT,
56836285Sbrian  "CCP status", "show cpp"},
56936285Sbrian  {"compress", NULL, sl_Show, LOCAL_AUTH,
57036285Sbrian  "VJ compression stats", "show compress"},
57136285Sbrian  {"escape", NULL, ShowEscape, LOCAL_AUTH | LOCAL_CX,
57236285Sbrian  "escape characters", "show escape"},
57336285Sbrian  {"filter", NULL, filter_Show, LOCAL_AUTH,
57436285Sbrian  "packet filters", "show filter [in|out|dial|alive]"},
57536285Sbrian  {"hdlc", NULL, hdlc_ReportStatus, LOCAL_AUTH | LOCAL_CX,
57636285Sbrian  "HDLC errors", "show hdlc"},
57736285Sbrian  {"ipcp", NULL, ipcp_Show, LOCAL_AUTH,
57836285Sbrian  "IPCP status", "show ipcp"},
57936285Sbrian  {"lcp", NULL, lcp_ReportStatus, LOCAL_AUTH | LOCAL_CX,
58036285Sbrian  "LCP status", "show lcp"},
58136285Sbrian  {"link", "datalink", datalink_Show, LOCAL_AUTH | LOCAL_CX,
58236285Sbrian  "(high-level) link info", "show link"},
58336285Sbrian  {"links", NULL, bundle_ShowLinks, LOCAL_AUTH,
58436285Sbrian  "available link names", "show links"},
58536285Sbrian  {"log", NULL, log_ShowLevel, LOCAL_AUTH,
58636285Sbrian  "log levels", "show log"},
58736285Sbrian  {"mem", NULL, mbuf_Show, LOCAL_AUTH,
58836285Sbrian  "mbuf allocations", "show mem"},
58936285Sbrian  {"modem", NULL, modem_ShowStatus, LOCAL_AUTH | LOCAL_CX,
59036285Sbrian  "(low-level) link info", "show modem"},
59136285Sbrian  {"mp", "multilink", mp_ShowStatus, LOCAL_AUTH,
59236285Sbrian  "multilink setup", "show mp"},
59336285Sbrian  {"proto", NULL, ShowProtocolStats, LOCAL_AUTH | LOCAL_CX_OPT,
59436285Sbrian  "protocol summary", "show proto"},
59536285Sbrian  {"route", NULL, route_Show, LOCAL_AUTH,
59636285Sbrian  "routing table", "show route"},
59736285Sbrian  {"stopped", NULL, ShowStopped, LOCAL_AUTH | LOCAL_CX,
59836285Sbrian  "STOPPED timeout", "show stopped"},
59936285Sbrian  {"timers", NULL, ShowTimerList, LOCAL_AUTH,
60036285Sbrian  "alarm timers", "show timers"},
60128679Sbrian  {"version", NULL, ShowVersion, LOCAL_NO_AUTH | LOCAL_AUTH,
60236285Sbrian  "version string", "show version"},
60336285Sbrian  {"who", NULL, log_ShowWho, LOCAL_AUTH,
60436285Sbrian  "client list", "show who"},
60528679Sbrian  {"help", "?", HelpCommand, LOCAL_NO_AUTH | LOCAL_AUTH,
60631343Sbrian  "Display this message", "show help|? [command]", ShowCommands},
60728679Sbrian  {NULL, NULL, NULL},
6086059Samurai};
6096059Samurai
61030715Sbrianstatic struct cmdtab const *
61131343SbrianFindCommand(struct cmdtab const *cmds, const char *str, int *pmatch)
6126059Samurai{
61326516Sbrian  int nmatch;
61426516Sbrian  int len;
61528679Sbrian  struct cmdtab const *found;
6166059Samurai
61726516Sbrian  found = NULL;
61826516Sbrian  len = strlen(str);
61926516Sbrian  nmatch = 0;
6206059Samurai  while (cmds->func) {
62125566Sbrian    if (cmds->name && strncasecmp(str, cmds->name, len) == 0) {
62226516Sbrian      if (cmds->name[len] == '\0') {
62328679Sbrian	*pmatch = 1;
62428679Sbrian	return cmds;
62526516Sbrian      }
6266059Samurai      nmatch++;
6276059Samurai      found = cmds;
62828679Sbrian    } else if (cmds->alias && strncasecmp(str, cmds->alias, len) == 0) {
62926516Sbrian      if (cmds->alias[len] == '\0') {
63028679Sbrian	*pmatch = 1;
63128679Sbrian	return cmds;
63226516Sbrian      }
6336059Samurai      nmatch++;
6346059Samurai      found = cmds;
6356059Samurai    }
6366059Samurai    cmds++;
6376059Samurai  }
6386059Samurai  *pmatch = nmatch;
63926516Sbrian  return found;
6406059Samurai}
6416059Samurai
64236285Sbrianstatic const char *
64336285SbrianmkPrefix(int argc, char const *const *argv, char *tgt, int sz)
64436285Sbrian{
64536285Sbrian  int f, tlen, len;
64636285Sbrian
64736285Sbrian  tlen = 0;
64836285Sbrian  for (f = 0; f < argc && tlen < sz - 2; f++) {
64936285Sbrian    if (f)
65036285Sbrian      tgt[tlen++] = ' ';
65136285Sbrian    len = strlen(argv[f]);
65236285Sbrian    if (len > sz - tlen - 1)
65336285Sbrian      len = sz - tlen - 1;
65436285Sbrian    strncpy(tgt+tlen, argv[f], len);
65536285Sbrian    tlen += len;
65636285Sbrian  }
65736285Sbrian  tgt[tlen] = '\0';
65836285Sbrian  return tgt;
65936285Sbrian}
66036285Sbrian
66130715Sbrianstatic int
66236285SbrianFindExec(struct bundle *bundle, struct cmdtab const *cmds, int argc, int argn,
66336285Sbrian         char const *const *argv, struct prompt *prompt, struct datalink *cx)
6646059Samurai{
66528679Sbrian  struct cmdtab const *cmd;
6666059Samurai  int val = 1;
6676059Samurai  int nmatch;
66831343Sbrian  struct cmdargs arg;
66936285Sbrian  char prefix[100];
6706059Samurai
67136285Sbrian  cmd = FindCommand(cmds, argv[argn], &nmatch);
6726059Samurai  if (nmatch > 1)
67336285Sbrian    log_Printf(LogWARN, "%s: Ambiguous command\n",
67436285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix));
67536285Sbrian  else if (cmd && (!prompt || (cmd->lauth & prompt->auth))) {
67636285Sbrian    if ((cmd->lauth & LOCAL_CX) && !cx)
67736285Sbrian      /* We've got no context, but we require it */
67836285Sbrian      cx = bundle2datalink(bundle, NULL);
67936285Sbrian
68036285Sbrian    if ((cmd->lauth & LOCAL_CX) && !cx)
68136285Sbrian      log_Printf(LogWARN, "%s: No context (use the `link' command)\n",
68236285Sbrian                mkPrefix(argn+1, argv, prefix, sizeof prefix));
68336285Sbrian    else {
68436285Sbrian      if (cx && !(cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
68536285Sbrian        log_Printf(LogWARN, "%s: Redundant context (%s) ignored\n",
68636285Sbrian                  mkPrefix(argn+1, argv, prefix, sizeof prefix), cx->name);
68736285Sbrian        cx = NULL;
68836285Sbrian      }
68936285Sbrian      arg.cmdtab = cmds;
69036285Sbrian      arg.cmd = cmd;
69136285Sbrian      arg.argc = argc;
69236285Sbrian      arg.argn = argn+1;
69336285Sbrian      arg.argv = argv;
69436285Sbrian      arg.bundle = bundle;
69536285Sbrian      arg.cx = cx;
69636285Sbrian      arg.prompt = prompt;
69736285Sbrian      val = (*cmd->func) (&arg);
69836285Sbrian    }
69931343Sbrian  } else
70036285Sbrian    log_Printf(LogWARN, "%s: Invalid command\n",
70136285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix));
70226516Sbrian
70326516Sbrian  if (val == -1)
70436285Sbrian    log_Printf(LogWARN, "Usage: %s\n", cmd->syntax);
70528679Sbrian  else if (val)
70636285Sbrian    log_Printf(LogWARN, "%s: Failed %d\n",
70736285Sbrian              mkPrefix(argn+1, argv, prefix, sizeof prefix), val);
70826516Sbrian
70926516Sbrian  return val;
7106059Samurai}
7116059Samurai
71237009Sbrianint
71337009Sbriancommand_Interpret(char *buff, int nb, char *argv[MAXARGS])
7146059Samurai{
7156059Samurai  char *cp;
7166059Samurai
7176059Samurai  if (nb > 0) {
7186059Samurai    cp = buff + strcspn(buff, "\r\n");
7196059Samurai    if (cp)
7206059Samurai      *cp = '\0';
72137009Sbrian    return MakeArgs(buff, argv, MAXARGS);
72237009Sbrian  }
72337009Sbrian  return 0;
72431121Sbrian}
7256059Samurai
72631822Sbrianstatic int
72731822Sbrianarghidden(int argc, char const *const *argv, int n)
72831822Sbrian{
72931822Sbrian  /* Is arg n of the given command to be hidden from the log ? */
73031828Sbrian
73131828Sbrian  /* set authkey xxxxx */
73231828Sbrian  /* set key xxxxx */
73331822Sbrian  if (n == 2 && !strncasecmp(argv[0], "se", 2) &&
73431822Sbrian      (!strncasecmp(argv[1], "authk", 5) || !strncasecmp(argv[1], "ke", 2)))
73531822Sbrian    return 1;
73631822Sbrian
73731828Sbrian  /* passwd xxxxx */
73831828Sbrian  if (n == 1 && !strncasecmp(argv[0], "p", 1))
73931828Sbrian    return 1;
74031828Sbrian
74136285Sbrian  /* set server port xxxxx .... */
74236285Sbrian  if (n == 3 && !strncasecmp(argv[0], "se", 2) &&
74336285Sbrian      !strncasecmp(argv[1], "se", 2))
74436285Sbrian    return 1;
74536285Sbrian
74631822Sbrian  return 0;
74731822Sbrian}
74831822Sbrian
74931121Sbrianvoid
75036285Sbriancommand_Run(struct bundle *bundle, int argc, char const *const *argv,
75137008Sbrian           struct prompt *prompt, const char *label, struct datalink *cx)
75231121Sbrian{
75331156Sbrian  if (argc > 0) {
75436285Sbrian    if (log_IsKept(LogCOMMAND)) {
75531156Sbrian      static char buf[LINE_LEN];
75631156Sbrian      int f, n;
75731156Sbrian
75831156Sbrian      *buf = '\0';
75931156Sbrian      if (label) {
76031962Sbrian        strncpy(buf, label, sizeof buf - 3);
76131962Sbrian        buf[sizeof buf - 3] = '\0';
76231156Sbrian        strcat(buf, ": ");
76331156Sbrian      }
76431156Sbrian      n = strlen(buf);
76531156Sbrian      for (f = 0; f < argc; f++) {
76631962Sbrian        if (n < sizeof buf - 1 && f)
76731156Sbrian          buf[n++] = ' ';
76831822Sbrian        if (arghidden(argc, argv, f))
76936285Sbrian          strncpy(buf+n, "********", sizeof buf - n - 1);
77031822Sbrian        else
77131962Sbrian          strncpy(buf+n, argv[f], sizeof buf - n - 1);
77231156Sbrian        n += strlen(buf+n);
77331156Sbrian      }
77436285Sbrian      log_Printf(LogCOMMAND, "%s\n", buf);
77531156Sbrian    }
77637008Sbrian    FindExec(bundle, Commands, argc, 0, argv, prompt, cx);
77731156Sbrian  }
7786059Samurai}
7796059Samurai
78031121Sbrianvoid
78136285Sbriancommand_Decode(struct bundle *bundle, char *buff, int nb, struct prompt *prompt,
78236285Sbrian              const char *label)
78331121Sbrian{
78431121Sbrian  int argc;
78537009Sbrian  char *argv[MAXARGS];
78631121Sbrian
78737009Sbrian  argc = command_Interpret(buff, nb, argv);
78837008Sbrian  command_Run(bundle, argc, (char const *const *)argv, prompt, label, NULL);
78931121Sbrian}
79031121Sbrian
7916059Samuraistatic int
79231343SbrianShowCommand(struct cmdargs const *arg)
7936059Samurai{
79436285Sbrian  if (!arg->prompt)
79536285Sbrian    log_Printf(LogWARN, "show: Cannot show without a prompt\n");
79636285Sbrian  else if (arg->argc > arg->argn)
79736285Sbrian    FindExec(arg->bundle, ShowCommands, arg->argc, arg->argn, arg->argv,
79836285Sbrian             arg->prompt, arg->cx);
7996059Samurai  else
80036285Sbrian    prompt_Printf(arg->prompt, "Use ``show ?'' to get a list.\n");
80126516Sbrian
80226516Sbrian  return 0;
8036059Samurai}
8046059Samurai
8056059Samuraistatic int
80631343SbrianTerminalCommand(struct cmdargs const *arg)
8076059Samurai{
80836285Sbrian  if (!arg->prompt) {
80936285Sbrian    log_Printf(LogWARN, "term: Need a prompt\n");
81026516Sbrian    return 1;
8116059Samurai  }
81236285Sbrian
81336285Sbrian  if (arg->cx->physical->link.lcp.fsm.state > ST_CLOSED) {
81436285Sbrian    prompt_Printf(arg->prompt, "LCP state is [%s]\n",
81536285Sbrian                  State2Nam(arg->cx->physical->link.lcp.fsm.state));
81636285Sbrian    return 1;
8176059Samurai  }
81836285Sbrian
81936285Sbrian  datalink_Up(arg->cx, 0, 0);
82036285Sbrian  prompt_TtyTermMode(arg->prompt, arg->cx);
82136285Sbrian  return 0;
8226059Samurai}
8236059Samurai
8246059Samuraistatic int
82531343SbrianQuitCommand(struct cmdargs const *arg)
8266059Samurai{
82736285Sbrian  if (!arg->prompt || prompt_IsController(arg->prompt) ||
82836285Sbrian      (arg->argc > arg->argn && !strcasecmp(arg->argv[arg->argn], "all") &&
82936285Sbrian       (arg->prompt->auth & LOCAL_AUTH)))
83036285Sbrian    Cleanup(EX_NORMAL);
83136285Sbrian  if (arg->prompt)
83236285Sbrian    prompt_Destroy(arg->prompt, 1);
83326516Sbrian
83426516Sbrian  return 0;
8356059Samurai}
8366059Samurai
8376059Samuraistatic int
83836285SbrianOpenCommand(struct cmdargs const *arg)
8396059Samurai{
84037160Sbrian  if (arg->argc == arg->argn)
84137993Sbrian    bundle_Open(arg->bundle, arg->cx ? arg->cx->name : NULL, PHYS_ALL, 1);
84237160Sbrian  else if (arg->argc == arg->argn + 1) {
84337160Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp")) {
84437385Sbrian      struct datalink *cx = arg->cx ?
84537385Sbrian        arg->cx : bundle2datalink(arg->bundle, NULL);
84637385Sbrian      if (cx) {
84737385Sbrian        if (cx->physical->link.lcp.fsm.state == ST_OPENED)
84837385Sbrian          fsm_Reopen(&cx->physical->link.lcp.fsm);
84937160Sbrian        else
85037993Sbrian          bundle_Open(arg->bundle, cx->name, PHYS_ALL, 1);
85137160Sbrian      } else
85237160Sbrian        log_Printf(LogWARN, "open lcp: You must specify a link\n");
85337160Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) {
85437160Sbrian      struct fsm *fp;
8556059Samurai
85637210Sbrian      fp = &command_ChooseLink(arg)->ccp.fsm;
85737160Sbrian      if (fp->link->lcp.fsm.state != ST_OPENED)
85837160Sbrian        log_Printf(LogWARN, "open: LCP must be open before opening CCP\n");
85937160Sbrian      else if (fp->state == ST_OPENED)
86037160Sbrian        fsm_Reopen(fp);
86137160Sbrian      else {
86237160Sbrian        fp->open_mode = 0;	/* Not passive any more */
86337160Sbrian        if (fp->state == ST_STOPPED) {
86437160Sbrian          fsm_Down(fp);
86537160Sbrian          fsm_Up(fp);
86637160Sbrian        } else {
86737160Sbrian          fsm_Up(fp);
86837160Sbrian          fsm_Open(fp);
86937160Sbrian        }
87036285Sbrian      }
87137160Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ipcp")) {
87237160Sbrian      if (arg->cx)
87337160Sbrian        log_Printf(LogWARN, "open ipcp: You need not specify a link\n");
87437160Sbrian      if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED)
87537160Sbrian        fsm_Reopen(&arg->bundle->ncp.ipcp.fsm);
87637160Sbrian      else
87737993Sbrian        bundle_Open(arg->bundle, NULL, PHYS_ALL, 1);
87837160Sbrian    } else
87937160Sbrian      return -1;
88036285Sbrian  } else
88136285Sbrian    return -1;
88236285Sbrian
88326516Sbrian  return 0;
8846059Samurai}
8856059Samurai
88625067Sbrianstatic int
88736285SbrianCloseCommand(struct cmdargs const *arg)
8886059Samurai{
88937007Sbrian  if (arg->argc == arg->argn)
89037007Sbrian    bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_STAYDOWN);
89137007Sbrian  else if (arg->argc == arg->argn + 1) {
89237007Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp"))
89337007Sbrian      bundle_Close(arg->bundle, arg->cx ? arg->cx->name : NULL, CLOSE_LCP);
89437007Sbrian    else if (!strcasecmp(arg->argv[arg->argn], "ccp") ||
89537007Sbrian             !strcasecmp(arg->argv[arg->argn], "ccp!")) {
89637007Sbrian      struct fsm *fp;
8976059Samurai
89837210Sbrian      fp = &command_ChooseLink(arg)->ccp.fsm;
89937007Sbrian      if (fp->state == ST_OPENED) {
90037007Sbrian        fsm_Close(fp);
90137007Sbrian        if (arg->argv[arg->argn][3] == '!')
90237007Sbrian          fp->open_mode = 0;		/* Stay ST_CLOSED */
90337007Sbrian        else
90437007Sbrian          fp->open_mode = OPEN_PASSIVE;	/* Wait for the peer to start */
90537007Sbrian      }
90637007Sbrian    } else
90736285Sbrian      return -1;
90836285Sbrian  } else
90936285Sbrian    return -1;
91036285Sbrian
91136285Sbrian  return 0;
9126059Samurai}
9136059Samurai
91425067Sbrianstatic int
91536285SbrianDownCommand(struct cmdargs const *arg)
91611336Samurai{
91737018Sbrian  if (arg->argc == arg->argn) {
91837018Sbrian      if (arg->cx)
91937018Sbrian        datalink_Down(arg->cx, CLOSE_STAYDOWN);
92037018Sbrian      else
92137018Sbrian        bundle_Down(arg->bundle, CLOSE_STAYDOWN);
92237018Sbrian  } else if (arg->argc == arg->argn + 1) {
92337018Sbrian    if (!strcasecmp(arg->argv[arg->argn], "lcp")) {
92437018Sbrian      if (arg->cx)
92537018Sbrian        datalink_Down(arg->cx, CLOSE_LCP);
92637018Sbrian      else
92737018Sbrian        bundle_Down(arg->bundle, CLOSE_LCP);
92837018Sbrian    } else if (!strcasecmp(arg->argv[arg->argn], "ccp")) {
92937018Sbrian      struct fsm *fp = arg->cx ? &arg->cx->physical->link.ccp.fsm :
93037018Sbrian                                 &arg->bundle->ncp.mp.link.ccp.fsm;
93137060Sbrian      fsm2initial(fp);
93237018Sbrian    } else
93337018Sbrian      return -1;
93436285Sbrian  } else
93536285Sbrian    return -1;
93636285Sbrian
93736285Sbrian  return 0;
93825067Sbrian}
93925067Sbrian
94025067Sbrianstatic int
94136285SbrianSetModemSpeed(struct cmdargs const *arg)
94225067Sbrian{
94336285Sbrian  long speed;
94436285Sbrian  char *end;
94511336Samurai
94636285Sbrian  if (arg->argc > arg->argn && *arg->argv[arg->argn]) {
94736285Sbrian    if (arg->argc > arg->argn+1) {
94836285Sbrian      log_Printf(LogWARN, "SetModemSpeed: Too many arguments");
94936285Sbrian      return -1;
95011336Samurai    }
95136285Sbrian    if (strcasecmp(arg->argv[arg->argn], "sync") == 0) {
95236285Sbrian      physical_SetSync(arg->cx->physical);
95336285Sbrian      return 0;
95436285Sbrian    }
95536285Sbrian    end = NULL;
95636285Sbrian    speed = strtol(arg->argv[arg->argn], &end, 10);
95736285Sbrian    if (*end) {
95836285Sbrian      log_Printf(LogWARN, "SetModemSpeed: Bad argument \"%s\"",
95936285Sbrian                arg->argv[arg->argn]);
96036285Sbrian      return -1;
96136285Sbrian    }
96236285Sbrian    if (physical_SetSpeed(arg->cx->physical, speed))
96336285Sbrian      return 0;
96436285Sbrian    log_Printf(LogWARN, "%s: Invalid speed\n", arg->argv[arg->argn]);
96536285Sbrian  } else
96636285Sbrian    log_Printf(LogWARN, "SetModemSpeed: No speed specified\n");
96724939Sbrian
96826516Sbrian  return -1;
96911336Samurai}
97011336Samurai
97125067Sbrianstatic int
97231343SbrianSetStoppedTimeout(struct cmdargs const *arg)
97328327Sbrian{
97436285Sbrian  struct link *l = &arg->cx->physical->link;
97536285Sbrian
97636285Sbrian  l->lcp.fsm.StoppedTimer.load = 0;
97736285Sbrian  l->ccp.fsm.StoppedTimer.load = 0;
97836285Sbrian  if (arg->argc <= arg->argn+2) {
97936285Sbrian    if (arg->argc > arg->argn) {
98036285Sbrian      l->lcp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn]) * SECTICKS;
98136285Sbrian      if (arg->argc > arg->argn+1)
98236285Sbrian        l->ccp.fsm.StoppedTimer.load = atoi(arg->argv[arg->argn+1]) * SECTICKS;
98328461Sbrian    }
98428327Sbrian    return 0;
98528327Sbrian  }
98628327Sbrian  return -1;
98728327Sbrian}
98828327Sbrian
98931081Sbrian#define ismask(x) \
99031081Sbrian  (*x == '0' && strlen(x) == 4 && strspn(x+1, "0123456789.") == 3)
99131081Sbrian
99228327Sbrianstatic int
99331343SbrianSetServer(struct cmdargs const *arg)
99426940Sbrian{
99526940Sbrian  int res = -1;
99626940Sbrian
99736285Sbrian  if (arg->argc > arg->argn && arg->argc < arg->argn+4) {
99831081Sbrian    const char *port, *passwd, *mask;
99931081Sbrian
100031081Sbrian    /* What's what ? */
100136285Sbrian    port = arg->argv[arg->argn];
100236285Sbrian    if (arg->argc == arg->argn + 2) {
100336285Sbrian      passwd = arg->argv[arg->argn+1];
100436285Sbrian      mask = NULL;
100536285Sbrian    } else if (arg->argc == arg->argn + 3) {
100636285Sbrian      passwd = arg->argv[arg->argn+1];
100736285Sbrian      mask = arg->argv[arg->argn+2];
100831081Sbrian      if (!ismask(mask))
100931081Sbrian        return -1;
101036285Sbrian    } else if (strcasecmp(port, "none") == 0) {
101136285Sbrian      if (server_Close(arg->bundle))
101236285Sbrian        log_Printf(LogPHASE, "Disabled server port.\n");
101336285Sbrian      return 0;
101431081Sbrian    } else
101536285Sbrian      return -1;
101631081Sbrian
101736285Sbrian    strncpy(server.passwd, passwd, sizeof server.passwd - 1);
101836285Sbrian    server.passwd[sizeof server.passwd - 1] = '\0';
101931081Sbrian
102036285Sbrian    if (*port == '/') {
102131081Sbrian      mode_t imask;
102236285Sbrian      char *ptr, name[LINE_LEN + 12];
102328679Sbrian
102431081Sbrian      if (mask != NULL) {
102528679Sbrian	unsigned m;
102628679Sbrian
102731081Sbrian	if (sscanf(mask, "%o", &m) == 1)
102831081Sbrian	  imask = m;
102931081Sbrian        else
103031081Sbrian          return -1;
103131081Sbrian      } else
103231081Sbrian        imask = (mode_t)-1;
103336285Sbrian
103436285Sbrian      ptr = strstr(port, "%d");
103536285Sbrian      if (ptr) {
103636285Sbrian        snprintf(name, sizeof name, "%.*s%d%s",
103737210Sbrian                 (int)(ptr - port), port, arg->bundle->unit, ptr + 2);
103836285Sbrian        port = name;
103936285Sbrian      }
104036285Sbrian      res = server_LocalOpen(arg->bundle, port, imask);
104127346Sbrian    } else {
104236285Sbrian      int iport, add = 0;
104328679Sbrian
104431081Sbrian      if (mask != NULL)
104531081Sbrian        return -1;
104628679Sbrian
104736285Sbrian      if (*port == '+') {
104836285Sbrian        port++;
104936285Sbrian        add = 1;
105036285Sbrian      }
105131081Sbrian      if (strspn(port, "0123456789") != strlen(port)) {
105231081Sbrian        struct servent *s;
105331081Sbrian
105431081Sbrian        if ((s = getservbyname(port, "tcp")) == NULL) {
105531081Sbrian	  iport = 0;
105636285Sbrian	  log_Printf(LogWARN, "%s: Invalid port or service\n", port);
105728679Sbrian	} else
105831081Sbrian	  iport = ntohs(s->s_port);
105927346Sbrian      } else
106031081Sbrian        iport = atoi(port);
106136285Sbrian
106236285Sbrian      if (iport) {
106336285Sbrian        if (add)
106436285Sbrian          iport += arg->bundle->unit;
106536285Sbrian        res = server_TcpOpen(arg->bundle, iport);
106636285Sbrian      } else
106736285Sbrian        res = -1;
106827346Sbrian    }
106931081Sbrian  }
107026940Sbrian
107126940Sbrian  return res;
107226940Sbrian}
107326940Sbrian
107426940Sbrianstatic int
107531343SbrianSetModemParity(struct cmdargs const *arg)
10766059Samurai{
107736285Sbrian  return arg->argc > arg->argn ? modem_SetParity(arg->cx->physical,
107836285Sbrian                                                 arg->argv[arg->argn]) : -1;
10796059Samurai}
10806059Samurai
10816059Samuraistatic int
108231343SbrianSetEscape(struct cmdargs const *arg)
10836059Samurai{
10846059Samurai  int code;
108536285Sbrian  int argc = arg->argc - arg->argn;
108636285Sbrian  char const *const *argv = arg->argv + arg->argn;
10876059Samurai
10886059Samurai  for (code = 0; code < 33; code++)
108936285Sbrian    arg->cx->physical->async.cfg.EscMap[code] = 0;
109031343Sbrian
10916059Samurai  while (argc-- > 0) {
10926059Samurai    sscanf(*argv++, "%x", &code);
10936059Samurai    code &= 0xff;
109436285Sbrian    arg->cx->physical->async.cfg.EscMap[code >> 3] |= (1 << (code & 7));
109536285Sbrian    arg->cx->physical->async.cfg.EscMap[32] = 1;
10966059Samurai  }
109726516Sbrian  return 0;
10986059Samurai}
10996059Samurai
110030715Sbrianstatic struct in_addr
110131343SbrianGetIpAddr(const char *cp)
11026059Samurai{
11036059Samurai  struct hostent *hp;
11046059Samurai  struct in_addr ipaddr;
11056059Samurai
110632124Sbrian  if (inet_aton(cp, &ipaddr) == 0) {
110732124Sbrian    hp = gethostbyname(cp);
110832124Sbrian    if (hp && hp->h_addrtype == AF_INET)
110932124Sbrian      memcpy(&ipaddr, hp->h_addr, hp->h_length);
111032124Sbrian    else
111132124Sbrian      ipaddr.s_addr = 0;
111232124Sbrian  }
111328679Sbrian  return (ipaddr);
11146059Samurai}
11156059Samurai
11166059Samuraistatic int
111731343SbrianSetInterfaceAddr(struct cmdargs const *arg)
11186059Samurai{
111936285Sbrian  struct ipcp *ipcp = &arg->bundle->ncp.ipcp;
112032267Sbrian  const char *hisaddr;
112132267Sbrian
112232267Sbrian  hisaddr = NULL;
112336285Sbrian  ipcp->cfg.my_range.ipaddr.s_addr = INADDR_ANY;
112436285Sbrian  ipcp->cfg.peer_range.ipaddr.s_addr = INADDR_ANY;
11256059Samurai
112636285Sbrian  if (arg->argc > arg->argn + 4)
112728679Sbrian    return -1;
112826516Sbrian
112936285Sbrian  ipcp->cfg.HaveTriggerAddress = 0;
113036285Sbrian  ipcp->cfg.netmask.s_addr = INADDR_ANY;
113136285Sbrian  iplist_reset(&ipcp->cfg.peer_list);
113228394Sbrian
113336285Sbrian  if (arg->argc > arg->argn) {
113436285Sbrian    if (!ParseAddr(ipcp, arg->argc - arg->argn, arg->argv + arg->argn,
113536285Sbrian                   &ipcp->cfg.my_range.ipaddr, &ipcp->cfg.my_range.mask,
113636285Sbrian                   &ipcp->cfg.my_range.width))
113728679Sbrian      return 1;
113836285Sbrian    if (arg->argc > arg->argn+1) {
113936285Sbrian      hisaddr = arg->argv[arg->argn+1];
114036285Sbrian      if (arg->argc > arg->argn+2) {
114136285Sbrian        ipcp->cfg.netmask = GetIpAddr(arg->argv[arg->argn+2]);
114236285Sbrian	if (arg->argc > arg->argn+3) {
114336285Sbrian	  ipcp->cfg.TriggerAddress = GetIpAddr(arg->argv[arg->argn+3]);
114436285Sbrian	  ipcp->cfg.HaveTriggerAddress = 1;
11459440Samurai	}
11466059Samurai      }
11476059Samurai    }
11486059Samurai  }
114928394Sbrian
11506059Samurai  /*
11516059Samurai   * For backwards compatibility, 0.0.0.0 means any address.
11526059Samurai   */
115336285Sbrian  if (ipcp->cfg.my_range.ipaddr.s_addr == INADDR_ANY) {
115436285Sbrian    ipcp->cfg.my_range.mask.s_addr = INADDR_ANY;
115536285Sbrian    ipcp->cfg.my_range.width = 0;
11566059Samurai  }
115736285Sbrian  ipcp->my_ip.s_addr = ipcp->cfg.my_range.ipaddr.s_addr;
115836285Sbrian
115936285Sbrian  if (ipcp->cfg.peer_range.ipaddr.s_addr == INADDR_ANY) {
116036285Sbrian    ipcp->cfg.peer_range.mask.s_addr = INADDR_ANY;
116136285Sbrian    ipcp->cfg.peer_range.width = 0;
11626059Samurai  }
116328537Sbrian
116436285Sbrian  if (hisaddr && !ipcp_UseHisaddr(arg->bundle, hisaddr,
116536928Sbrian                                  arg->bundle->phys_type.all & PHYS_AUTO))
116632267Sbrian    return 4;
116731121Sbrian
116826516Sbrian  return 0;
11696059Samurai}
11706059Samurai
117118752Sjkhstatic int
117231343SbrianSetVariable(struct cmdargs const *arg)
11736059Samurai{
117437210Sbrian  long long_val, param = (long)arg->cmd->args;
117537210Sbrian  int mode, dummyint;
117631343Sbrian  const char *argp;
117736285Sbrian  struct datalink *cx = arg->cx;	/* LOCAL_CX uses this */
117836285Sbrian  const char *err = NULL;
117936285Sbrian  struct link *l = command_ChooseLink(arg);	/* LOCAL_CX_OPT uses this */
118036285Sbrian  struct in_addr dummyaddr, *addr;
11816059Samurai
118236285Sbrian  if (arg->argc > arg->argn)
118336285Sbrian    argp = arg->argv[arg->argn];
118426551Sbrian  else
118531343Sbrian    argp = "";
118626551Sbrian
118736285Sbrian  if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
118836285Sbrian    log_Printf(LogWARN, "set %s: No context (use the `link' command)\n",
118936285Sbrian              arg->cmd->name);
119036285Sbrian    return 1;
119136285Sbrian  } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
119236285Sbrian    log_Printf(LogWARN, "set %s: Redundant context (%s) ignored\n",
119336285Sbrian              arg->cmd->name, cx->name);
119436285Sbrian    cx = NULL;
119536285Sbrian  }
119636285Sbrian
119726551Sbrian  switch (param) {
119828679Sbrian  case VAR_AUTHKEY:
119936285Sbrian    if (bundle_Phase(arg->bundle) == PHASE_DEAD) {
120036285Sbrian      strncpy(arg->bundle->cfg.auth.key, argp,
120136285Sbrian              sizeof arg->bundle->cfg.auth.key - 1);
120236285Sbrian      arg->bundle->cfg.auth.key[sizeof arg->bundle->cfg.auth.key - 1] = '\0';
120336285Sbrian    } else {
120436285Sbrian      err = "set authkey: Only available at phase DEAD\n";
120536285Sbrian      log_Printf(LogWARN, err);
120636285Sbrian    }
120728679Sbrian    break;
120837210Sbrian
120928679Sbrian  case VAR_AUTHNAME:
121036285Sbrian    if (bundle_Phase(arg->bundle) == PHASE_DEAD) {
121136285Sbrian      strncpy(arg->bundle->cfg.auth.name, argp,
121236285Sbrian              sizeof arg->bundle->cfg.auth.name - 1);
121336285Sbrian      arg->bundle->cfg.auth.name[sizeof arg->bundle->cfg.auth.name - 1] = '\0';
121436285Sbrian    } else {
121536285Sbrian      err = "set authname: Only available at phase DEAD\n";
121636285Sbrian      log_Printf(LogWARN, err);
121736285Sbrian    }
121828679Sbrian    break;
121937210Sbrian
122036285Sbrian  case VAR_AUTOLOAD:
122136285Sbrian    if (arg->argc == arg->argn + 2 || arg->argc == arg->argn + 4) {
122236285Sbrian      arg->bundle->autoload.running = 1;
122336285Sbrian      arg->bundle->cfg.autoload.max.timeout = atoi(arg->argv[arg->argn]);
122436285Sbrian      arg->bundle->cfg.autoload.max.packets = atoi(arg->argv[arg->argn + 1]);
122536285Sbrian      if (arg->argc == arg->argn + 4) {
122636285Sbrian        arg->bundle->cfg.autoload.min.timeout = atoi(arg->argv[arg->argn + 2]);
122736285Sbrian        arg->bundle->cfg.autoload.min.packets = atoi(arg->argv[arg->argn + 3]);
122836285Sbrian      } else {
122936285Sbrian        arg->bundle->cfg.autoload.min.timeout = 0;
123036285Sbrian        arg->bundle->cfg.autoload.min.packets = 0;
123136285Sbrian      }
123236285Sbrian    } else {
123336285Sbrian      err = "Set autoload requires two or four arguments\n";
123436285Sbrian      log_Printf(LogWARN, err);
123536285Sbrian    }
123636285Sbrian    break;
123737210Sbrian
123828679Sbrian  case VAR_DIAL:
123936285Sbrian    strncpy(cx->cfg.script.dial, argp, sizeof cx->cfg.script.dial - 1);
124036285Sbrian    cx->cfg.script.dial[sizeof cx->cfg.script.dial - 1] = '\0';
124128679Sbrian    break;
124237210Sbrian
124328679Sbrian  case VAR_LOGIN:
124436285Sbrian    strncpy(cx->cfg.script.login, argp, sizeof cx->cfg.script.login - 1);
124536285Sbrian    cx->cfg.script.login[sizeof cx->cfg.script.login - 1] = '\0';
124628679Sbrian    break;
124737210Sbrian
124836285Sbrian  case VAR_WINSIZE:
124936285Sbrian    if (arg->argc > arg->argn) {
125036285Sbrian      l->ccp.cfg.deflate.out.winsize = atoi(arg->argv[arg->argn]);
125136285Sbrian      if (l->ccp.cfg.deflate.out.winsize < 8 ||
125236285Sbrian          l->ccp.cfg.deflate.out.winsize > 15) {
125336285Sbrian          log_Printf(LogWARN, "%d: Invalid outgoing window size\n",
125436285Sbrian                    l->ccp.cfg.deflate.out.winsize);
125536285Sbrian          l->ccp.cfg.deflate.out.winsize = 15;
125636285Sbrian      }
125736285Sbrian      if (arg->argc > arg->argn+1) {
125836285Sbrian        l->ccp.cfg.deflate.in.winsize = atoi(arg->argv[arg->argn+1]);
125936285Sbrian        if (l->ccp.cfg.deflate.in.winsize < 8 ||
126036285Sbrian            l->ccp.cfg.deflate.in.winsize > 15) {
126136285Sbrian            log_Printf(LogWARN, "%d: Invalid incoming window size\n",
126236285Sbrian                      l->ccp.cfg.deflate.in.winsize);
126336285Sbrian            l->ccp.cfg.deflate.in.winsize = 15;
126436285Sbrian        }
126536285Sbrian      } else
126636285Sbrian        l->ccp.cfg.deflate.in.winsize = 0;
126736285Sbrian    } else {
126836285Sbrian      err = "No window size specified\n";
126936285Sbrian      log_Printf(LogWARN, err);
127036285Sbrian    }
127136285Sbrian    break;
127237210Sbrian
127328679Sbrian  case VAR_DEVICE:
127436285Sbrian    physical_SetDeviceList(cx->physical, arg->argc - arg->argn,
127536285Sbrian                           arg->argv + arg->argn);
127636285Sbrian    break;
127737210Sbrian
127836285Sbrian  case VAR_ACCMAP:
127936285Sbrian    if (arg->argc > arg->argn) {
128037210Sbrian      u_long ulong_val;
128136285Sbrian      sscanf(argp, "%lx", &ulong_val);
128237210Sbrian      cx->physical->link.lcp.cfg.accmap = (u_int32_t)ulong_val;
128336285Sbrian    } else {
128436285Sbrian      err = "No accmap specified\n";
128536285Sbrian      log_Printf(LogWARN, err);
128636285Sbrian    }
128736285Sbrian    break;
128837210Sbrian
128936285Sbrian  case VAR_MODE:
129036285Sbrian    mode = Nam2mode(argp);
129136285Sbrian    if (mode == PHYS_NONE || mode == PHYS_ALL) {
129236285Sbrian      log_Printf(LogWARN, "%s: Invalid mode\n", argp);
129336285Sbrian      return -1;
129436285Sbrian    }
129536285Sbrian    bundle_SetMode(arg->bundle, cx, mode);
129636285Sbrian    break;
129737210Sbrian
129836285Sbrian  case VAR_MRRU:
129937210Sbrian    if (bundle_Phase(arg->bundle) != PHASE_DEAD) {
130036285Sbrian      log_Printf(LogWARN, "mrru: Only changable at phase DEAD\n");
130137210Sbrian      return 1;
130229696Sbrian    }
130337210Sbrian    long_val = atol(argp);
130437210Sbrian    if (long_val && long_val < MIN_MRU) {
130537210Sbrian      log_Printf(LogWARN, "MRRU %ld: too small - min %d\n", long_val, MIN_MRU);
130637210Sbrian      return 1;
130737210Sbrian    } else if (long_val > MAX_MRU) {
130837210Sbrian      log_Printf(LogWARN, "MRRU %ld: too big - max %d\n", long_val, MAX_MRU);
130937210Sbrian      return 1;
131037210Sbrian    } else
131137210Sbrian      arg->bundle->ncp.mp.cfg.mrru = long_val;
131228679Sbrian    break;
131337210Sbrian
131436285Sbrian  case VAR_MRU:
131537210Sbrian    long_val = atol(argp);
131637210Sbrian    if (long_val == 0)
131737210Sbrian      l->lcp.cfg.mru = DEF_MRU;
131837210Sbrian    else if (long_val < MIN_MRU) {
131937210Sbrian      log_Printf(LogWARN, "MRU %ld: too small - min %d\n", long_val, MIN_MRU);
132037210Sbrian      return 1;
132137210Sbrian    } else if (long_val > MAX_MRU) {
132237210Sbrian      log_Printf(LogWARN, "MRU %ld: too big - max %d\n", long_val, MAX_MRU);
132337210Sbrian      return 1;
132437210Sbrian    } else
132537210Sbrian      l->lcp.cfg.mru = long_val;
132628679Sbrian    break;
132737210Sbrian
132836285Sbrian  case VAR_MTU:
132937210Sbrian    long_val = atol(argp);
133037210Sbrian    if (long_val && long_val < MIN_MTU) {
133137210Sbrian      log_Printf(LogWARN, "MTU %ld: too small - min %d\n", long_val, MIN_MTU);
133237210Sbrian      return 1;
133337210Sbrian    } else if (long_val > MAX_MTU) {
133437210Sbrian      log_Printf(LogWARN, "MTU %ld: too big - max %d\n", long_val, MAX_MTU);
133537210Sbrian      return 1;
133637210Sbrian    } else
133737210Sbrian      arg->bundle->cfg.mtu = long_val;
133836285Sbrian    break;
133937210Sbrian
134036285Sbrian  case VAR_OPENMODE:
134136285Sbrian    if (strcasecmp(argp, "active") == 0)
134236285Sbrian      cx->physical->link.lcp.cfg.openmode = arg->argc > arg->argn+1 ?
134336285Sbrian        atoi(arg->argv[arg->argn+1]) : 1;
134436285Sbrian    else if (strcasecmp(argp, "passive") == 0)
134536285Sbrian      cx->physical->link.lcp.cfg.openmode = OPEN_PASSIVE;
134636285Sbrian    else {
134736285Sbrian      err = "%s: Invalid openmode\n";
134836285Sbrian      log_Printf(LogWARN, err, argp);
134936285Sbrian    }
135036285Sbrian    break;
135137210Sbrian
135228679Sbrian  case VAR_PHONE:
135336285Sbrian    strncpy(cx->cfg.phone.list, argp, sizeof cx->cfg.phone.list - 1);
135436285Sbrian    cx->cfg.phone.list[sizeof cx->cfg.phone.list - 1] = '\0';
135538174Sbrian    cx->phone.alt = cx->phone.next = NULL;
135628679Sbrian    break;
135737210Sbrian
135828679Sbrian  case VAR_HANGUP:
135936285Sbrian    strncpy(cx->cfg.script.hangup, argp, sizeof cx->cfg.script.hangup - 1);
136036285Sbrian    cx->cfg.script.hangup[sizeof cx->cfg.script.hangup - 1] = '\0';
136128679Sbrian    break;
136237210Sbrian
136336285Sbrian  case VAR_IDLETIMEOUT:
136436285Sbrian    if (arg->argc > arg->argn+1)
136536285Sbrian      err = "Too many idle timeout values\n";
136636285Sbrian    else if (arg->argc == arg->argn+1)
136736285Sbrian      bundle_SetIdleTimer(arg->bundle, atoi(argp));
136836285Sbrian    if (err)
136936285Sbrian      log_Printf(LogWARN, err);
137029549Sbrian    break;
137137210Sbrian
137236285Sbrian  case VAR_LQRPERIOD:
137337210Sbrian    long_val = atol(argp);
137437210Sbrian    if (long_val < MIN_LQRPERIOD) {
137537210Sbrian      log_Printf(LogWARN, "%ld: Invalid lqr period - min %d\n",
137637210Sbrian                 long_val, MIN_LQRPERIOD);
137737210Sbrian      return 1;
137836285Sbrian    } else
137937210Sbrian      l->lcp.cfg.lqrperiod = long_val;
138036285Sbrian    break;
138137210Sbrian
138236285Sbrian  case VAR_LCPRETRY:
138337210Sbrian    long_val = atol(argp);
138437210Sbrian    if (long_val < MIN_FSMRETRY) {
138537210Sbrian      log_Printf(LogWARN, "%ld: Invalid LCP FSM retry period - min %d\n",
138637210Sbrian                 long_val, MIN_FSMRETRY);
138737210Sbrian      return 1;
138836285Sbrian    } else
138937210Sbrian      cx->physical->link.lcp.cfg.fsmretry = long_val;
139036285Sbrian    break;
139137210Sbrian
139236285Sbrian  case VAR_CHAPRETRY:
139337210Sbrian    long_val = atol(argp);
139437210Sbrian    if (long_val < MIN_FSMRETRY) {
139537210Sbrian      log_Printf(LogWARN, "%ld: Invalid CHAP FSM retry period - min %d\n",
139637210Sbrian                 long_val, MIN_FSMRETRY);
139737210Sbrian      return 1;
139836285Sbrian    } else
139937210Sbrian      cx->chap.auth.cfg.fsmretry = long_val;
140036285Sbrian    break;
140137210Sbrian
140236285Sbrian  case VAR_PAPRETRY:
140337210Sbrian    long_val = atol(argp);
140437210Sbrian    if (long_val < MIN_FSMRETRY) {
140537210Sbrian      log_Printf(LogWARN, "%ld: Invalid PAP FSM retry period - min %d\n",
140637210Sbrian                 long_val, MIN_FSMRETRY);
140737210Sbrian      return 1;
140836285Sbrian    } else
140937210Sbrian      cx->pap.cfg.fsmretry = long_val;
141036285Sbrian    break;
141137210Sbrian
141236285Sbrian  case VAR_CCPRETRY:
141337210Sbrian    long_val = atol(argp);
141437210Sbrian    if (long_val < MIN_FSMRETRY) {
141537210Sbrian      log_Printf(LogWARN, "%ld: Invalid CCP FSM retry period - min %d\n",
141637210Sbrian                 long_val, MIN_FSMRETRY);
141737210Sbrian      return 1;
141836285Sbrian    } else
141937210Sbrian      l->ccp.cfg.fsmretry = long_val;
142036285Sbrian    break;
142137210Sbrian
142236285Sbrian  case VAR_IPCPRETRY:
142337210Sbrian    long_val = atol(argp);
142437210Sbrian    if (long_val < MIN_FSMRETRY) {
142537210Sbrian      log_Printf(LogWARN, "%ld: Invalid IPCP FSM retry period - min %d\n",
142637210Sbrian                 long_val, MIN_FSMRETRY);
142737210Sbrian      return 1;
142836285Sbrian    } else
142937210Sbrian      arg->bundle->ncp.ipcp.cfg.fsmretry = long_val;
143036285Sbrian    break;
143137210Sbrian
143236285Sbrian  case VAR_NBNS:
143336285Sbrian  case VAR_DNS:
143436285Sbrian    if (param == VAR_DNS)
143536285Sbrian      addr = arg->bundle->ncp.ipcp.cfg.ns.dns;
143636285Sbrian    else
143736285Sbrian      addr = arg->bundle->ncp.ipcp.cfg.ns.nbns;
143836285Sbrian
143936285Sbrian    addr[0].s_addr = addr[1].s_addr = INADDR_ANY;
144036285Sbrian
144136285Sbrian    if (arg->argc > arg->argn) {
144236285Sbrian      ParseAddr(&arg->bundle->ncp.ipcp, 1, arg->argv + arg->argn,
144336285Sbrian                addr, &dummyaddr, &dummyint);
144436285Sbrian      if (arg->argc > arg->argn+1)
144536285Sbrian        ParseAddr(&arg->bundle->ncp.ipcp, 1, arg->argv + arg->argn + 1,
144636285Sbrian                  addr + 1, &dummyaddr, &dummyint);
144736285Sbrian
144836285Sbrian      if (addr[1].s_addr == INADDR_ANY)
144936285Sbrian        addr[1].s_addr = addr[0].s_addr;
145036285Sbrian      if (addr[0].s_addr == INADDR_ANY)
145136285Sbrian        addr[0].s_addr = addr[1].s_addr;
145236285Sbrian    }
145336285Sbrian    break;
145438174Sbrian
145538174Sbrian  case VAR_CALLBACK:
145638174Sbrian    cx->cfg.callback.opmask = 0;
145738174Sbrian    for (dummyint = arg->argn; dummyint < arg->argc; dummyint++) {
145838174Sbrian      if (!strcasecmp(arg->argv[dummyint], "auth"))
145938174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_AUTH);
146038174Sbrian      else if (!strcasecmp(arg->argv[dummyint], "cbcp"))
146138174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_CBCP);
146238174Sbrian      else if (!strcasecmp(arg->argv[dummyint], "e.164")) {
146338174Sbrian        if (dummyint == arg->argc - 1)
146438174Sbrian          log_Printf(LogWARN, "No E.164 arg (E.164 ignored) !\n");
146538174Sbrian        else {
146638174Sbrian          cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_E164);
146738174Sbrian          strncpy(cx->cfg.callback.msg, arg->argv[++dummyint],
146838174Sbrian                  sizeof cx->cfg.callback.msg - 1);
146938174Sbrian          cx->cfg.callback.msg[sizeof cx->cfg.callback.msg - 1] = '\0';
147038174Sbrian        }
147138174Sbrian      } else if (!strcasecmp(arg->argv[dummyint], "none"))
147238174Sbrian        cx->cfg.callback.opmask |= CALLBACK_BIT(CALLBACK_NONE);
147338174Sbrian      else
147438174Sbrian        return -1;
147538174Sbrian    }
147638174Sbrian    if (cx->cfg.callback.opmask == CALLBACK_BIT(CALLBACK_NONE))
147738174Sbrian      cx->cfg.callback.opmask = 0;
147838174Sbrian    break;
147938174Sbrian
148038174Sbrian  case VAR_CBCP:
148138174Sbrian    cx->cfg.cbcp.delay = 0;
148238174Sbrian    *cx->cfg.cbcp.phone = '\0';
148338174Sbrian    cx->cfg.cbcp.fsmretry = DEF_FSMRETRY;
148438174Sbrian    if (arg->argc > arg->argn) {
148538174Sbrian      strncpy(cx->cfg.cbcp.phone, arg->argv[arg->argn],
148638174Sbrian              sizeof cx->cfg.cbcp.phone - 1);
148738174Sbrian      cx->cfg.cbcp.phone[sizeof cx->cfg.cbcp.phone - 1] = '\0';
148838174Sbrian      if (arg->argc > arg->argn + 1) {
148938174Sbrian        cx->cfg.cbcp.delay = atoi(arg->argv[arg->argn + 1]);
149038174Sbrian        if (arg->argc > arg->argn + 2) {
149138174Sbrian          long_val = atol(arg->argv[arg->argn + 2]);
149238174Sbrian          if (long_val < MIN_FSMRETRY)
149338174Sbrian            log_Printf(LogWARN, "%ld: Invalid CBCP FSM retry period - min %d\n",
149438174Sbrian                       long_val, MIN_FSMRETRY);
149538174Sbrian          else
149638174Sbrian            cx->cfg.cbcp.fsmretry = long_val;
149738174Sbrian        }
149838174Sbrian      }
149938174Sbrian    }
150038174Sbrian    break;
150138544Sbrian
150238544Sbrian  case VAR_CHOKED:
150338544Sbrian    arg->bundle->cfg.choked.timeout = atoi(argp);
150438544Sbrian    if (arg->bundle->cfg.choked.timeout <= 0)
150538544Sbrian      arg->bundle->cfg.choked.timeout = CHOKED_TIMEOUT;
150638544Sbrian    break;
150738544Sbrian
15086059Samurai  }
150936285Sbrian
151036285Sbrian  return err ? 1 : 0;
15116059Samurai}
15126059Samurai
151328679Sbrianstatic int
151431343SbrianSetCtsRts(struct cmdargs const *arg)
151520812Sjkh{
151636285Sbrian  if (arg->argc == arg->argn+1) {
151736285Sbrian    if (strcmp(arg->argv[arg->argn], "on") == 0)
151836285Sbrian      physical_SetRtsCts(arg->cx->physical, 1);
151936285Sbrian    else if (strcmp(arg->argv[arg->argn], "off") == 0)
152036285Sbrian      physical_SetRtsCts(arg->cx->physical, 0);
152120812Sjkh    else
152226516Sbrian      return -1;
152326516Sbrian    return 0;
152420812Sjkh  }
152526516Sbrian  return -1;
152620812Sjkh}
152720812Sjkh
152830715Sbrianstatic struct cmdtab const SetCommands[] = {
152936285Sbrian  {"accmap", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
153036285Sbrian  "accmap value", "set accmap hex-value", (const void *)VAR_ACCMAP},
153128679Sbrian  {"authkey", "key", SetVariable, LOCAL_AUTH,
153236285Sbrian  "authentication key", "set authkey|key key", (const void *)VAR_AUTHKEY},
153328679Sbrian  {"authname", NULL, SetVariable, LOCAL_AUTH,
153436285Sbrian  "authentication name", "set authname name", (const void *)VAR_AUTHNAME},
153536285Sbrian  {"autoload", NULL, SetVariable, LOCAL_AUTH,
153636285Sbrian  "auto link [de]activation", "set autoload maxtime maxload mintime minload",
153736285Sbrian  (const void *)VAR_AUTOLOAD},
153838174Sbrian  {"callback", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
153938174Sbrian  "callback control", "set callback [none|auth|cbcp|"
154038174Sbrian  "E.164 *|number[,number]...]...", (const void *)VAR_CALLBACK},
154138174Sbrian  {"cbcp", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
154238174Sbrian  "CBCP control", "set cbcp [*|phone[,phone...] [delay [timeout]]]",
154338174Sbrian  (const void *)VAR_CBCP},
154436285Sbrian  {"ccpretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
154536285Sbrian  "FSM retry period", "set ccpretry value", (const void *)VAR_CCPRETRY},
154636285Sbrian  {"chapretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
154736285Sbrian  "CHAP retry period", "set chapretry value", (const void *)VAR_CHAPRETRY},
154838544Sbrian  {"choked", NULL, SetVariable, LOCAL_AUTH,
154938544Sbrian  "choked timeout", "set choked [secs]", (const void *)VAR_CHOKED},
155036285Sbrian  {"ctsrts", "crtscts", SetCtsRts, LOCAL_AUTH | LOCAL_CX,
155136285Sbrian  "Use hardware flow control", "set ctsrts [on|off]"},
155236285Sbrian  {"deflate", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
155336285Sbrian  "deflate window sizes", "set deflate out-winsize in-winsize",
155436285Sbrian  (const void *) VAR_WINSIZE},
155536285Sbrian  {"device", "line", SetVariable, LOCAL_AUTH | LOCAL_CX,
155636285Sbrian  "modem device name", "set device|line device-name[,device-name]",
155736285Sbrian  (const void *) VAR_DEVICE},
155836285Sbrian  {"dial", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
155936285Sbrian  "dialing script", "set dial chat-script", (const void *) VAR_DIAL},
156036285Sbrian  {"dns", NULL, SetVariable, LOCAL_AUTH, "Domain Name Server",
156136285Sbrian  "set dns pri-addr [sec-addr]", (const void *)VAR_DNS},
156236285Sbrian  {"enddisc", NULL, mp_SetEnddisc, LOCAL_AUTH,
156336285Sbrian  "Endpoint Discriminator", "set enddisc [IP|magic|label|psn value]"},
156436285Sbrian  {"escape", NULL, SetEscape, LOCAL_AUTH | LOCAL_CX,
156536285Sbrian  "escape characters", "set escape hex-digit ..."},
156636285Sbrian  {"filter", NULL, filter_Set, LOCAL_AUTH,
156736285Sbrian  "packet filters", "set filter alive|dial|in|out rule-no permit|deny "
156836285Sbrian  "[src_addr[/width]] [dst_addr[/width]] [tcp|udp|icmp [src [lt|eq|gt port]] "
156936285Sbrian  "[dst [lt|eq|gt port]] [estab] [syn] [finrst]]"},
157036285Sbrian  {"hangup", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
157136285Sbrian  "hangup script", "set hangup chat-script", (const void *) VAR_HANGUP},
157236285Sbrian  {"ifaddr", NULL, SetInterfaceAddr, LOCAL_AUTH, "destination address",
157331343Sbrian  "set ifaddr [src-addr [dst-addr [netmask [trg-addr]]]]"},
157436285Sbrian  {"ipcpretry", NULL, SetVariable, LOCAL_AUTH,
157536285Sbrian  "FSM retry period", "set ipcpretry value", (const void *)VAR_IPCPRETRY},
157636285Sbrian  {"lcpretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
157736285Sbrian  "FSM retry period", "set lcpretry value", (const void *)VAR_LCPRETRY},
157836712Sbrian  {"log", NULL, log_SetLevel, LOCAL_AUTH, "log level",
157936712Sbrian  "set log [local] [+|-]async|ccp|chat|command|connect|debug|hdlc|id0|ipcp|"
158036712Sbrian  "lcp|lqm|phase|tcp/ip|timer|tun..."},
158136285Sbrian  {"login", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
158236285Sbrian  "login script", "set login chat-script", (const void *) VAR_LOGIN},
158336285Sbrian  {"lqrperiod", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
158436285Sbrian  "LQR period", "set lqrperiod value", (const void *)VAR_LQRPERIOD},
158536285Sbrian  {"mode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "mode value",
158636285Sbrian  "set mode interactive|auto|ddial|background", (const void *)VAR_MODE},
158736285Sbrian  {"mrru", NULL, SetVariable, LOCAL_AUTH, "MRRU value",
158836285Sbrian  "set mrru value", (const void *)VAR_MRRU},
158936285Sbrian  {"mru", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX_OPT,
159036285Sbrian  "MRU value", "set mru value", (const void *)VAR_MRU},
159136285Sbrian  {"mtu", NULL, SetVariable, LOCAL_AUTH,
159236285Sbrian  "interface MTU value", "set mtu value", (const void *)VAR_MTU},
159336285Sbrian  {"nbns", NULL, SetVariable, LOCAL_AUTH, "NetBIOS Name Server",
159436285Sbrian  "set nbns pri-addr [sec-addr]", (const void *)VAR_NBNS},
159536285Sbrian  {"openmode", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "open mode",
159636285Sbrian  "set openmode active|passive [secs]", (const void *)VAR_OPENMODE},
159736285Sbrian  {"papretry", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
159836285Sbrian  "PAP retry period", "set papretry value", (const void *)VAR_PAPRETRY},
159936285Sbrian  {"parity", NULL, SetModemParity, LOCAL_AUTH | LOCAL_CX,
160036285Sbrian  "modem parity", "set parity [odd|even|none]"},
160136285Sbrian  {"phone", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX, "telephone number(s)",
160236285Sbrian  "set phone phone1[:phone2[...]]", (const void *)VAR_PHONE},
160336285Sbrian  {"reconnect", NULL, datalink_SetReconnect, LOCAL_AUTH | LOCAL_CX,
160436285Sbrian  "Reconnect timeout", "set reconnect value ntries"},
160536285Sbrian  {"redial", NULL, datalink_SetRedial, LOCAL_AUTH | LOCAL_CX,
160636285Sbrian  "Redial timeout", "set redial value|random[.value|random] [attempts]"},
160728679Sbrian  {"server", "socket", SetServer, LOCAL_AUTH,
160836774Sbrian  "server port", "set server|socket TcpPort|LocalName|none password [mask]"},
160936285Sbrian  {"speed", NULL, SetModemSpeed, LOCAL_AUTH | LOCAL_CX,
161036285Sbrian  "modem speed", "set speed value"},
161136285Sbrian  {"stopped", NULL, SetStoppedTimeout, LOCAL_AUTH | LOCAL_CX,
161236285Sbrian  "STOPPED timeouts", "set stopped [LCPseconds [CCPseconds]]"},
161336285Sbrian  {"timeout", NULL, SetVariable, LOCAL_AUTH, "Idle timeout",
161436285Sbrian  "set timeout idletime", (const void *)VAR_IDLETIMEOUT},
161536285Sbrian  {"vj", NULL, ipcp_vjset, LOCAL_AUTH,
161636285Sbrian  "vj values", "set vj slots|slotcomp [value]"},
161736285Sbrian  {"weight", NULL, mp_SetDatalinkWeight, LOCAL_AUTH | LOCAL_CX,
161836285Sbrian  "datalink weighting", "set weight n"},
161928679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
162031343Sbrian  "Display this message", "set help|? [command]", SetCommands},
162128679Sbrian  {NULL, NULL, NULL},
16226059Samurai};
16236059Samurai
16246059Samuraistatic int
162531343SbrianSetCommand(struct cmdargs const *arg)
16266059Samurai{
162736285Sbrian  if (arg->argc > arg->argn)
162836285Sbrian    FindExec(arg->bundle, SetCommands, arg->argc, arg->argn, arg->argv,
162936285Sbrian             arg->prompt, arg->cx);
163036285Sbrian  else if (arg->prompt)
163136285Sbrian    prompt_Printf(arg->prompt, "Use `set ?' to get a list or `set ? <var>' for"
163226516Sbrian	    " syntax help.\n");
16336059Samurai  else
163436285Sbrian    log_Printf(LogWARN, "set command must have arguments\n");
163526516Sbrian
163626516Sbrian  return 0;
16376059Samurai}
16386059Samurai
16396059Samurai
16406059Samuraistatic int
164131343SbrianAddCommand(struct cmdargs const *arg)
16426059Samurai{
16436059Samurai  struct in_addr dest, gateway, netmask;
164436285Sbrian  int gw, addrs;
16456059Samurai
164636285Sbrian  if (arg->argc != arg->argn+3 && arg->argc != arg->argn+2)
164731598Sbrian    return -1;
164831598Sbrian
164936285Sbrian  addrs = 0;
165036285Sbrian  if (arg->argc == arg->argn+2) {
165136285Sbrian    if (!strcasecmp(arg->argv[arg->argn], "default"))
165236285Sbrian      dest.s_addr = netmask.s_addr = INADDR_ANY;
165331598Sbrian    else {
165436285Sbrian      int width;
165536285Sbrian
165636285Sbrian      if (!ParseAddr(&arg->bundle->ncp.ipcp, 1, arg->argv + arg->argn,
165736285Sbrian	             &dest, &netmask, &width))
165836285Sbrian        return -1;
165936285Sbrian      if (!strncasecmp(arg->argv[arg->argn], "MYADDR", 6))
166036285Sbrian        addrs = ROUTE_DSTMYADDR;
166136285Sbrian      else if (!strncasecmp(arg->argv[arg->argn], "HISADDR", 7))
166236285Sbrian        addrs = ROUTE_DSTHISADDR;
166331598Sbrian    }
166436285Sbrian    gw = 1;
166534536Sbrian  } else {
166636285Sbrian    if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
166736285Sbrian      addrs = ROUTE_DSTMYADDR;
166836285Sbrian      dest = arg->bundle->ncp.ipcp.my_ip;
166936285Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
167036285Sbrian      addrs = ROUTE_DSTHISADDR;
167136285Sbrian      dest = arg->bundle->ncp.ipcp.peer_ip;
167236285Sbrian    } else
167336285Sbrian      dest = GetIpAddr(arg->argv[arg->argn]);
167436285Sbrian    netmask = GetIpAddr(arg->argv[arg->argn+1]);
167531598Sbrian    gw = 2;
16766059Samurai  }
167736285Sbrian
167836285Sbrian  if (strcasecmp(arg->argv[arg->argn+gw], "HISADDR") == 0) {
167936285Sbrian    gateway = arg->bundle->ncp.ipcp.peer_ip;
168036285Sbrian    addrs |= ROUTE_GWHISADDR;
168136285Sbrian  } else if (strcasecmp(arg->argv[arg->argn+gw], "INTERFACE") == 0)
168231598Sbrian    gateway.s_addr = INADDR_ANY;
168331598Sbrian  else
168436285Sbrian    gateway = GetIpAddr(arg->argv[arg->argn+gw]);
168536285Sbrian
168636285Sbrian  if (bundle_SetRoute(arg->bundle, RTM_ADD, dest, gateway, netmask,
168737927Sbrian                  arg->cmd->args ? 1 : 0, (addrs & ROUTE_GWHISADDR) ? 1 : 0))
168836285Sbrian    route_Add(&arg->bundle->ncp.ipcp.route, addrs, dest, netmask, gateway);
168936285Sbrian
169031598Sbrian  return 0;
16916059Samurai}
16926059Samurai
16936059Samuraistatic int
169431343SbrianDeleteCommand(struct cmdargs const *arg)
16956059Samurai{
169631598Sbrian  struct in_addr dest, none;
169736285Sbrian  int addrs;
16986059Samurai
169936285Sbrian  if (arg->argc == arg->argn+1) {
170036285Sbrian    if(strcasecmp(arg->argv[arg->argn], "all") == 0) {
170136285Sbrian      route_IfDelete(arg->bundle, 0);
170236285Sbrian      route_DeleteAll(&arg->bundle->ncp.ipcp.route);
170336285Sbrian    } else {
170436285Sbrian      addrs = 0;
170536285Sbrian      if (strcasecmp(arg->argv[arg->argn], "MYADDR") == 0) {
170636285Sbrian        dest = arg->bundle->ncp.ipcp.my_ip;
170736285Sbrian        addrs = ROUTE_DSTMYADDR;
170836285Sbrian      } else if (strcasecmp(arg->argv[arg->argn], "HISADDR") == 0) {
170936285Sbrian        dest = arg->bundle->ncp.ipcp.peer_ip;
171036285Sbrian        addrs = ROUTE_DSTHISADDR;
171136285Sbrian      } else {
171236285Sbrian        if (strcasecmp(arg->argv[arg->argn], "default") == 0)
171336285Sbrian          dest.s_addr = INADDR_ANY;
171436285Sbrian        else
171536285Sbrian          dest = GetIpAddr(arg->argv[arg->argn]);
171636285Sbrian        addrs = ROUTE_STATIC;
171736285Sbrian      }
171831598Sbrian      none.s_addr = INADDR_ANY;
171936285Sbrian      bundle_SetRoute(arg->bundle, RTM_DELETE, dest, none, none,
172037927Sbrian                      arg->cmd->args ? 1 : 0, 0);
172136285Sbrian      route_Delete(&arg->bundle->ncp.ipcp.route, addrs, dest);
172231598Sbrian    }
172334536Sbrian  } else
172426516Sbrian    return -1;
172526516Sbrian
172626516Sbrian  return 0;
17276059Samurai}
17286059Samurai
172931343Sbrian#ifndef NOALIAS
173026031Sbrianstatic struct cmdtab const AliasCommands[] =
173126031Sbrian{
173236285Sbrian  {"addr", NULL, alias_RedirectAddr, LOCAL_AUTH,
173336285Sbrian   "static address translation", "alias addr [addr_local addr_alias]"},
173436285Sbrian  {"deny_incoming", NULL, AliasOption, LOCAL_AUTH,
173536285Sbrian   "stop incoming connections", "alias deny_incoming [yes|no]",
173636285Sbrian   (const void *) PKT_ALIAS_DENY_INCOMING},
173728679Sbrian  {"enable", NULL, AliasEnable, LOCAL_AUTH,
173836285Sbrian   "enable IP aliasing", "alias enable [yes|no]"},
173928679Sbrian  {"log", NULL, AliasOption, LOCAL_AUTH,
174036285Sbrian   "log aliasing link creation", "alias log [yes|no]",
174136285Sbrian   (const void *) PKT_ALIAS_LOG},
174236285Sbrian  {"port", NULL, alias_RedirectPort, LOCAL_AUTH,
174336285Sbrian   "port redirection", "alias port [proto addr_local:port_local  port_alias]"},
174428679Sbrian  {"same_ports", NULL, AliasOption, LOCAL_AUTH,
174536285Sbrian   "try to leave port numbers unchanged", "alias same_ports [yes|no]",
174636285Sbrian   (const void *) PKT_ALIAS_SAME_PORTS},
174736285Sbrian  {"unregistered_only", NULL, AliasOption, LOCAL_AUTH,
174836285Sbrian   "alias unregistered (private) IP address space only",
174936285Sbrian   "alias unregistered_only [yes|no]",
175036285Sbrian   (const void *) PKT_ALIAS_UNREGISTERED_ONLY},
175128679Sbrian  {"use_sockets", NULL, AliasOption, LOCAL_AUTH,
175236285Sbrian   "allocate host sockets", "alias use_sockets [yes|no]",
175336285Sbrian   (const void *) PKT_ALIAS_USE_SOCKETS},
175428679Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
175536285Sbrian   "Display this message", "alias help|? [command]", AliasCommands},
175628679Sbrian  {NULL, NULL, NULL},
175726031Sbrian};
175826031Sbrian
175926031Sbrian
176026031Sbrianstatic int
176131343SbrianAliasCommand(struct cmdargs const *arg)
176226031Sbrian{
176336285Sbrian  if (arg->argc > arg->argn)
176436285Sbrian    FindExec(arg->bundle, AliasCommands, arg->argc, arg->argn, arg->argv,
176536285Sbrian             arg->prompt, arg->cx);
176636285Sbrian  else if (arg->prompt)
176736285Sbrian    prompt_Printf(arg->prompt, "Use `alias help' to get a list or `alias help"
176836285Sbrian            " <option>' for syntax help.\n");
176926031Sbrian  else
177036285Sbrian    log_Printf(LogWARN, "alias command must have arguments\n");
177126516Sbrian
177226516Sbrian  return 0;
177326031Sbrian}
177426031Sbrian
177526031Sbrianstatic int
177631343SbrianAliasEnable(struct cmdargs const *arg)
177726031Sbrian{
177836285Sbrian  if (arg->argc == arg->argn+1) {
177936285Sbrian    if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
178037191Sbrian      arg->bundle->AliasEnabled = 1;
178137191Sbrian      return 0;
178236285Sbrian    } else if (strcasecmp(arg->argv[arg->argn], "no") == 0) {
178337191Sbrian      arg->bundle->AliasEnabled = 0;
178426516Sbrian      return 0;
178526142Sbrian    }
178635449Sbrian  }
178736285Sbrian
178826516Sbrian  return -1;
178926031Sbrian}
179026031Sbrian
179126031Sbrian
179226031Sbrianstatic int
179331343SbrianAliasOption(struct cmdargs const *arg)
179426031Sbrian{
179536285Sbrian  unsigned param = (unsigned)arg->cmd->args;
179636285Sbrian  if (arg->argc == arg->argn+1) {
179736285Sbrian    if (strcasecmp(arg->argv[arg->argn], "yes") == 0) {
179837191Sbrian      if (arg->bundle->AliasEnabled) {
179937191Sbrian	PacketAliasSetMode(param, param);
180028679Sbrian	return 0;
180128679Sbrian      }
180236285Sbrian      log_Printf(LogWARN, "alias not enabled\n");
180336285Sbrian    } else if (strcmp(arg->argv[arg->argn], "no") == 0) {
180437191Sbrian      if (arg->bundle->AliasEnabled) {
180537191Sbrian	PacketAliasSetMode(0, param);
180628679Sbrian	return 0;
180728679Sbrian      }
180836285Sbrian      log_Printf(LogWARN, "alias not enabled\n");
180928679Sbrian    }
181035449Sbrian  }
181128679Sbrian  return -1;
181226031Sbrian}
181331343Sbrian#endif /* #ifndef NOALIAS */
181431121Sbrian
181531121Sbrianstatic struct cmdtab const AllowCommands[] = {
181636285Sbrian  {"modes", "mode", AllowModes, LOCAL_AUTH,
181736285Sbrian  "Only allow certain ppp modes", "allow modes mode..."},
181831121Sbrian  {"users", "user", AllowUsers, LOCAL_AUTH,
181931121Sbrian  "Allow users access to ppp", "allow users logname..."},
182031121Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
182131343Sbrian  "Display this message", "allow help|? [command]", AllowCommands},
182231121Sbrian  {NULL, NULL, NULL},
182331121Sbrian};
182431121Sbrian
182531121Sbrianstatic int
182631343SbrianAllowCommand(struct cmdargs const *arg)
182731121Sbrian{
182836285Sbrian  /* arg->bundle may be NULL (see system_IsValid()) ! */
182936285Sbrian  if (arg->argc > arg->argn)
183036285Sbrian    FindExec(arg->bundle, AllowCommands, arg->argc, arg->argn, arg->argv,
183136285Sbrian             arg->prompt, arg->cx);
183236285Sbrian  else if (arg->prompt)
183336285Sbrian    prompt_Printf(arg->prompt, "Use `allow ?' to get a list or `allow ? <cmd>'"
183436285Sbrian                  " for syntax help.\n");
183531121Sbrian  else
183636285Sbrian    log_Printf(LogWARN, "allow command must have arguments\n");
183731121Sbrian
183831121Sbrian  return 0;
183931121Sbrian}
184036285Sbrian
184136285Sbrianstatic int
184236285SbrianLinkCommand(struct cmdargs const *arg)
184336285Sbrian{
184436285Sbrian  if (arg->argc > arg->argn+1) {
184536285Sbrian    char namelist[LINE_LEN];
184636285Sbrian    struct datalink *cx;
184736285Sbrian    char *name;
184836285Sbrian    int result = 0;
184936285Sbrian
185036285Sbrian    if (!strcmp(arg->argv[arg->argn], "*")) {
185136285Sbrian      struct datalink *dl;
185236285Sbrian
185336285Sbrian      cx = arg->bundle->links;
185436285Sbrian      while (cx) {
185536285Sbrian        /* Watch it, the command could be a ``remove'' */
185636285Sbrian        dl = cx->next;
185736285Sbrian        FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
185836285Sbrian                 arg->prompt, cx);
185936285Sbrian        for (cx = arg->bundle->links; cx; cx = cx->next)
186036285Sbrian          if (cx == dl)
186136285Sbrian            break;		/* Pointer's still valid ! */
186236285Sbrian      }
186336285Sbrian    } else {
186436285Sbrian      strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
186536285Sbrian      namelist[sizeof namelist - 1] = '\0';
186636285Sbrian      for(name = strtok(namelist, ", "); name; name = strtok(NULL,", "))
186736285Sbrian        if (!bundle2datalink(arg->bundle, name)) {
186836285Sbrian          log_Printf(LogWARN, "link: %s: Invalid link name\n", name);
186936285Sbrian          return 1;
187036285Sbrian        }
187136285Sbrian
187236285Sbrian      strncpy(namelist, arg->argv[arg->argn], sizeof namelist - 1);
187336285Sbrian      namelist[sizeof namelist - 1] = '\0';
187436285Sbrian      for(name = strtok(namelist, ", "); name; name = strtok(NULL,", ")) {
187536285Sbrian        cx = bundle2datalink(arg->bundle, name);
187636285Sbrian        if (cx)
187736285Sbrian          FindExec(arg->bundle, Commands, arg->argc, arg->argn+1, arg->argv,
187836285Sbrian                   arg->prompt, cx);
187936285Sbrian        else {
188036285Sbrian          log_Printf(LogWARN, "link: %s: Invalidated link name !\n", name);
188136285Sbrian          result++;
188236285Sbrian        }
188336285Sbrian      }
188436285Sbrian    }
188536285Sbrian    return result;
188636285Sbrian  }
188736285Sbrian
188836285Sbrian  log_Printf(LogWARN, "Usage: %s\n", arg->cmd->syntax);
188936285Sbrian  return 2;
189036285Sbrian}
189136285Sbrian
189236285Sbrianstruct link *
189336285Sbriancommand_ChooseLink(struct cmdargs const *arg)
189436285Sbrian{
189536285Sbrian  if (arg->cx)
189636285Sbrian    return &arg->cx->physical->link;
189737210Sbrian  else if (!arg->bundle->ncp.mp.cfg.mrru) {
189836285Sbrian    struct datalink *dl = bundle2datalink(arg->bundle, NULL);
189937210Sbrian    if (dl)
190037210Sbrian      return &dl->physical->link;
190136285Sbrian  }
190237210Sbrian  return &arg->bundle->ncp.mp.link;
190336285Sbrian}
190436285Sbrian
190536285Sbrianstatic const char *
190636285Sbrianident_cmd(const char *cmd, unsigned *keep, unsigned *add)
190736285Sbrian{
190836285Sbrian  const char *result;
190936285Sbrian
191036285Sbrian  switch (*cmd) {
191136285Sbrian    case 'A':
191236285Sbrian    case 'a':
191336285Sbrian      result = "accept";
191436285Sbrian      *keep = NEG_MYMASK;
191536285Sbrian      *add = NEG_ACCEPTED;
191636285Sbrian      break;
191736285Sbrian    case 'D':
191836285Sbrian    case 'd':
191936285Sbrian      switch (cmd[1]) {
192036285Sbrian        case 'E':
192136285Sbrian        case 'e':
192236285Sbrian          result = "deny";
192336285Sbrian          *keep = NEG_MYMASK;
192436285Sbrian          *add = 0;
192536285Sbrian          break;
192636285Sbrian        case 'I':
192736285Sbrian        case 'i':
192836285Sbrian          result = "disable";
192936285Sbrian          *keep = NEG_HISMASK;
193036285Sbrian          *add = 0;
193136285Sbrian          break;
193236285Sbrian        default:
193336285Sbrian          return NULL;
193436285Sbrian      }
193536285Sbrian      break;
193636285Sbrian    case 'E':
193736285Sbrian    case 'e':
193836285Sbrian      result = "enable";
193936285Sbrian      *keep = NEG_HISMASK;
194036285Sbrian      *add = NEG_ENABLED;
194136285Sbrian      break;
194236285Sbrian    default:
194336285Sbrian      return NULL;
194436285Sbrian  }
194536285Sbrian
194636285Sbrian  return result;
194736285Sbrian}
194836285Sbrian
194936285Sbrianstatic int
195036285SbrianOptSet(struct cmdargs const *arg)
195136285Sbrian{
195237574Sbrian  int bit = (int)(long)arg->cmd->args;
195336285Sbrian  const char *cmd;
195436285Sbrian  unsigned keep;			/* Keep these bits */
195536285Sbrian  unsigned add;				/* Add these bits */
195636285Sbrian
195736285Sbrian  if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL)
195836285Sbrian    return 1;
195936285Sbrian
196036285Sbrian  if (add)
196136285Sbrian    arg->bundle->cfg.opt |= bit;
196236285Sbrian  else
196336285Sbrian    arg->bundle->cfg.opt &= ~bit;
196436285Sbrian  return 0;
196536285Sbrian}
196636285Sbrian
196736285Sbrianstatic int
196836285SbrianNegotiateSet(struct cmdargs const *arg)
196936285Sbrian{
197037210Sbrian  long param = (long)arg->cmd->args;
197136285Sbrian  struct link *l = command_ChooseLink(arg);	/* LOCAL_CX_OPT uses this */
197236285Sbrian  struct datalink *cx = arg->cx;	/* LOCAL_CX uses this */
197336285Sbrian  const char *cmd;
197436285Sbrian  unsigned keep;			/* Keep these bits */
197536285Sbrian  unsigned add;				/* Add these bits */
197636285Sbrian
197736285Sbrian  if ((cmd = ident_cmd(arg->argv[arg->argn-2], &keep, &add)) == NULL)
197836285Sbrian    return 1;
197936285Sbrian
198036285Sbrian  if ((arg->cmd->lauth & LOCAL_CX) && !cx) {
198136285Sbrian    log_Printf(LogWARN, "%s %s: No context (use the `link' command)\n",
198236285Sbrian              cmd, arg->cmd->name);
198336285Sbrian    return 2;
198436285Sbrian  } else if (cx && !(arg->cmd->lauth & (LOCAL_CX|LOCAL_CX_OPT))) {
198536285Sbrian    log_Printf(LogWARN, "%s %s: Redundant context (%s) ignored\n",
198636285Sbrian              cmd, arg->cmd->name, cx->name);
198736285Sbrian    cx = NULL;
198836285Sbrian  }
198936285Sbrian
199036285Sbrian  switch (param) {
199136285Sbrian    case NEG_ACFCOMP:
199236285Sbrian      cx->physical->link.lcp.cfg.acfcomp &= keep;
199336285Sbrian      cx->physical->link.lcp.cfg.acfcomp |= add;
199436285Sbrian      break;
199536285Sbrian    case NEG_CHAP:
199636285Sbrian      cx->physical->link.lcp.cfg.chap &= keep;
199736285Sbrian      cx->physical->link.lcp.cfg.chap |= add;
199836285Sbrian      break;
199936285Sbrian    case NEG_DEFLATE:
200036285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE] &= keep;
200136285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE] |= add;
200236285Sbrian      break;
200336285Sbrian    case NEG_DNS:
200436285Sbrian      arg->bundle->ncp.ipcp.cfg.ns.dns_neg &= keep;
200536285Sbrian      arg->bundle->ncp.ipcp.cfg.ns.dns_neg |= add;
200636285Sbrian      break;
200736285Sbrian    case NEG_LQR:
200836285Sbrian      cx->physical->link.lcp.cfg.lqr &= keep;
200936285Sbrian      cx->physical->link.lcp.cfg.lqr |= add;
201036285Sbrian      break;
201136285Sbrian    case NEG_PAP:
201236285Sbrian      cx->physical->link.lcp.cfg.pap &= keep;
201336285Sbrian      cx->physical->link.lcp.cfg.pap |= add;
201436285Sbrian      break;
201536285Sbrian    case NEG_PPPDDEFLATE:
201636285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE24] &= keep;
201736285Sbrian      l->ccp.cfg.neg[CCP_NEG_DEFLATE24] |= add;
201836285Sbrian      break;
201936285Sbrian    case NEG_PRED1:
202036285Sbrian      l->ccp.cfg.neg[CCP_NEG_PRED1] &= keep;
202136285Sbrian      l->ccp.cfg.neg[CCP_NEG_PRED1] |= add;
202236285Sbrian      break;
202336285Sbrian    case NEG_PROTOCOMP:
202436285Sbrian      cx->physical->link.lcp.cfg.protocomp &= keep;
202536285Sbrian      cx->physical->link.lcp.cfg.protocomp |= add;
202636285Sbrian      break;
202736285Sbrian    case NEG_SHORTSEQ:
202836285Sbrian      if (bundle_Phase(arg->bundle) != PHASE_DEAD)
202936285Sbrian        log_Printf(LogWARN, "shortseq: Only changable at phase DEAD\n");
203036285Sbrian      else {
203136285Sbrian        arg->bundle->ncp.mp.cfg.shortseq &= keep;
203236285Sbrian        arg->bundle->ncp.mp.cfg.shortseq |= add;
203336285Sbrian      }
203436285Sbrian      break;
203536285Sbrian    case NEG_VJCOMP:
203636285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.neg &= keep;
203736285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.neg |= add;
203836285Sbrian      break;
203936285Sbrian  }
204036285Sbrian
204136285Sbrian  return 0;
204236285Sbrian}
204336285Sbrian
204436285Sbrianstatic struct cmdtab const NegotiateCommands[] = {
204536285Sbrian  {"idcheck", NULL, OptSet, LOCAL_AUTH, "Check FSM reply ids",
204636285Sbrian  "disable|enable", (const void *)OPT_IDCHECK},
204736285Sbrian  {"loopback", NULL, OptSet, LOCAL_AUTH, "Loop packets for local iface",
204836285Sbrian  "disable|enable", (const void *)OPT_LOOPBACK},
204936285Sbrian  {"passwdauth", NULL, OptSet, LOCAL_AUTH, "Use passwd file",
205036285Sbrian  "disable|enable", (const void *)OPT_PASSWDAUTH},
205136285Sbrian  {"proxy", NULL, OptSet, LOCAL_AUTH, "Create proxy ARP entry",
205236285Sbrian  "disable|enable", (const void *)OPT_PROXY},
205336285Sbrian  {"sroutes", NULL, OptSet, LOCAL_AUTH, "Use sticky routes",
205436285Sbrian  "disable|enable", (const void *)OPT_SROUTES},
205536285Sbrian  {"throughput", NULL, OptSet, LOCAL_AUTH, "Rolling throughput",
205636285Sbrian  "disable|enable", (const void *)OPT_THROUGHPUT},
205736285Sbrian  {"utmp", NULL, OptSet, LOCAL_AUTH, "Log connections in utmp",
205836285Sbrian  "disable|enable", (const void *)OPT_UTMP},
205936285Sbrian
206036285Sbrian#define OPT_MAX 7	/* accept/deny allowed below and not above */
206136285Sbrian
206236285Sbrian  {"acfcomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
206336285Sbrian  "Address & Control field compression", "accept|deny|disable|enable",
206436285Sbrian  (const void *)NEG_ACFCOMP},
206536285Sbrian  {"chap", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
206636285Sbrian  "Challenge Handshake Authentication Protocol", "accept|deny|disable|enable",
206736285Sbrian  (const void *)NEG_CHAP},
206836285Sbrian  {"deflate", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
206936285Sbrian  "Deflate compression", "accept|deny|disable|enable",
207036285Sbrian  (const void *)NEG_DEFLATE},
207136285Sbrian  {"deflate24", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
207236285Sbrian  "Deflate (type 24) compression", "accept|deny|disable|enable",
207336285Sbrian  (const void *)NEG_PPPDDEFLATE},
207436285Sbrian  {"dns", NULL, NegotiateSet, LOCAL_AUTH,
207536285Sbrian  "DNS specification", "accept|deny|disable|enable", (const void *)NEG_DNS},
207636285Sbrian  {"lqr", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
207736285Sbrian  "Link Quality Reports", "accept|deny|disable|enable",
207836285Sbrian  (const void *)NEG_LQR},
207936285Sbrian  {"pap", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
208036285Sbrian  "Password Authentication protocol", "accept|deny|disable|enable",
208136285Sbrian  (const void *)NEG_PAP},
208236285Sbrian  {"pred1", "predictor1", NegotiateSet, LOCAL_AUTH | LOCAL_CX_OPT,
208336285Sbrian  "Predictor 1 compression", "accept|deny|disable|enable",
208436285Sbrian  (const void *)NEG_PRED1},
208536285Sbrian  {"protocomp", NULL, NegotiateSet, LOCAL_AUTH | LOCAL_CX,
208636285Sbrian  "Protocol field compression", "accept|deny|disable|enable",
208736285Sbrian  (const void *)NEG_PROTOCOMP},
208836285Sbrian  {"shortseq", NULL, NegotiateSet, LOCAL_AUTH,
208936285Sbrian  "MP Short Sequence Numbers", "accept|deny|disable|enable",
209036285Sbrian  (const void *)NEG_SHORTSEQ},
209136285Sbrian  {"vjcomp", NULL, NegotiateSet, LOCAL_AUTH,
209236285Sbrian  "Van Jacobson header compression", "accept|deny|disable|enable",
209336285Sbrian  (const void *)NEG_VJCOMP},
209436285Sbrian  {"help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH,
209536285Sbrian  "Display this message", "accept|deny|disable|enable help|? [value]",
209636285Sbrian  NegotiateCommands},
209736285Sbrian  {NULL, NULL, NULL},
209836285Sbrian};
209936285Sbrian
210036285Sbrianstatic int
210136285SbrianNegotiateCommand(struct cmdargs const *arg)
210236285Sbrian{
210336285Sbrian  if (arg->argc > arg->argn) {
210436285Sbrian    char const *argv[3];
210536285Sbrian    unsigned keep, add;
210636285Sbrian    int n;
210736285Sbrian
210836285Sbrian    if ((argv[0] = ident_cmd(arg->argv[arg->argn-1], &keep, &add)) == NULL)
210936285Sbrian      return -1;
211036285Sbrian    argv[2] = NULL;
211136285Sbrian
211236285Sbrian    for (n = arg->argn; n < arg->argc; n++) {
211336285Sbrian      argv[1] = arg->argv[n];
211436285Sbrian      FindExec(arg->bundle, NegotiateCommands + (keep == NEG_HISMASK ?
211536285Sbrian               0 : OPT_MAX), 2, 1, argv, arg->prompt, arg->cx);
211636285Sbrian    }
211736285Sbrian  } else if (arg->prompt)
211836285Sbrian    prompt_Printf(arg->prompt, "Use `%s ?' to get a list.\n",
211936285Sbrian	    arg->argv[arg->argn-1]);
212036285Sbrian  else
212136285Sbrian    log_Printf(LogWARN, "%s command must have arguments\n",
212236285Sbrian              arg->argv[arg->argn] );
212336285Sbrian
212436285Sbrian  return 0;
212536285Sbrian}
212636285Sbrian
212736285Sbrianconst char *
212836285Sbriancommand_ShowNegval(unsigned val)
212936285Sbrian{
213036285Sbrian  switch (val&3) {
213136285Sbrian    case 1: return "disabled & accepted";
213236285Sbrian    case 2: return "enabled & denied";
213336285Sbrian    case 3: return "enabled & accepted";
213436285Sbrian  }
213536285Sbrian  return "disabled & denied";
213636285Sbrian}
213736934Sbrian
213836934Sbrianstatic int
213936934SbrianClearCommand(struct cmdargs const *arg)
214036934Sbrian{
214136934Sbrian  struct pppThroughput *t;
214236934Sbrian  struct datalink *cx;
214336934Sbrian  int i, clear_type;
214436934Sbrian
214536934Sbrian  if (arg->argc < arg->argn + 1)
214636934Sbrian    return -1;
214736934Sbrian
214836934Sbrian  if (strcasecmp(arg->argv[arg->argn], "modem") == 0) {
214936934Sbrian    cx = arg->cx;
215036934Sbrian    if (!cx)
215136934Sbrian      cx = bundle2datalink(arg->bundle, NULL);
215236934Sbrian    if (!cx) {
215336934Sbrian      log_Printf(LogWARN, "A link must be specified for ``clear modem''\n");
215436934Sbrian      return 1;
215536934Sbrian    }
215636934Sbrian    t = &cx->physical->link.throughput;
215736934Sbrian  } else if (strcasecmp(arg->argv[arg->argn], "ipcp") == 0)
215836934Sbrian    t = &arg->bundle->ncp.ipcp.throughput;
215936934Sbrian  else
216036934Sbrian    return -1;
216136934Sbrian
216236934Sbrian  if (arg->argc > arg->argn + 1) {
216336934Sbrian    clear_type = 0;
216436934Sbrian    for (i = arg->argn + 1; i < arg->argc; i++)
216536934Sbrian      if (strcasecmp(arg->argv[i], "overall") == 0)
216636934Sbrian        clear_type |= THROUGHPUT_OVERALL;
216736934Sbrian      else if (strcasecmp(arg->argv[i], "current") == 0)
216836934Sbrian        clear_type |= THROUGHPUT_CURRENT;
216936934Sbrian      else if (strcasecmp(arg->argv[i], "peak") == 0)
217036934Sbrian        clear_type |= THROUGHPUT_PEAK;
217136934Sbrian      else
217236934Sbrian        return -1;
217336934Sbrian  } else
217436934Sbrian    clear_type = THROUGHPUT_ALL;
217536934Sbrian
217636934Sbrian  throughput_clear(t, clear_type, arg->prompt);
217736934Sbrian  return 0;
217836934Sbrian}
2179