command.c revision 6059
1/*
2 *		PPP User command processing module
3 *
4 *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5 *
6 *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
7 *
8 * Redistribution and use in source and binary forms are permitted
9 * provided that the above copyright notice and this paragraph are
10 * duplicated in all such forms and that any documentation,
11 * advertising materials, and other materials related to such
12 * distribution and use acknowledge that the software was developed
13 * by the Internet Initiative Japan, Inc.  The name of the
14 * IIJ may not be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 *
20 * $Id:$
21 *
22 */
23#include <ctype.h>
24#include "fsm.h"
25#include "phase.h"
26#include "lcp.h"
27#include "ipcp.h"
28#include "modem.h"
29#include "command.h"
30#include "hdlc.h"
31#include "vars.h"
32#include <netdb.h>
33#include <sys/socket.h>
34#include <arpa/inet.h>
35#include <net/route.h>
36#include "os.h"
37
38extern int  MakeArgs();
39extern void Cleanup(), TtyTermMode(), PacketMode();
40extern int  EnableCommand(), DisableCommand(), DisplayCommand();
41extern int  AcceptCommand(), DenyCommand();
42extern int  LoadCommand(), SaveCommand();
43extern int  ChangeParity(char *);
44extern int  SelectSystem();
45extern int  ShowRoute();
46
47struct in_addr ifnetmask;
48
49static int ShowCommand(), TerminalCommand(), QuitCommand();
50static int CloseCommand(), DialCommand(), DownCommand();
51static int SetCommand(), AddCommand(), DeleteCommand();
52
53static int
54HelpCommand(list, argc, argv, plist)
55struct cmdtab *list;
56int argc;
57char **argv;
58struct cmdtab *plist;
59{
60  struct cmdtab *cmd;
61  int n;
62  char c;
63
64  if (argc > 0) {
65    for (cmd = plist; cmd->name; cmd++) {
66      if (strcmp(cmd->name, *argv) == 0) {
67        printf("%s %s\n", cmd->name, cmd->syntax);
68        return(1);
69      }
70    }
71    return(1);
72  }
73  n = 0;
74  for (cmd = plist; cmd->func; cmd++) {
75    c = (n & 1)? '\n' : '\t';
76    if (cmd->name) {
77      printf("  %-8s: %-20s%c", cmd->name, cmd->helpmes, c);
78      n++;
79    }
80  }
81  if (n & 1)
82    printf("\n");
83  return(1);
84}
85
86int
87IsInteractive()
88{
89  char *mes = NULL;
90
91  if (mode & MODE_AUTO)
92    mes = "Working as auto mode.";
93  else if (mode & MODE_DIRECT)
94    mes = "Working as direct mode.";
95  else if (mode & MODE_DEDICATED)
96    mes = "Workring as dedicated mode.";
97  if (mes) {
98    printf("%s\n", mes);
99    return(0);
100  }
101  return(1);
102}
103
104static int
105DialCommand(cmdlist, argc, argv)
106struct cmdtab *cmdlist;
107int argc;
108char **argv;
109{
110  if (LcpFsm.state > ST_CLOSED) {
111    printf("LCP state is [%s]\n", StateNames[LcpFsm.state]);
112    return(1);
113  }
114  if (!IsInteractive())
115    return(1);
116  modem = OpenModem(mode);
117  if (modem < 0) {
118    printf("failed to open modem.\n");
119    modem = 0;
120    return(1);
121  }
122  if (argc > 0) {
123    if (SelectSystem(*argv, CONFFILE) < 0) {
124      printf("%s: not found.\n", *argv);
125      return(1);
126    }
127  }
128  if (DialModem()) {
129    sleep(1);
130    ModemTimeout();
131    PacketMode();
132  }
133  return(1);
134}
135
136static char StrOption[] = "option ..";
137static char StrRemote[] = "[remote]";
138char StrNull[] = "";
139
140struct cmdtab Commands[] = {
141  { "accept",  NULL,    AcceptCommand,
142  	"accept option request",	StrOption },
143  { "add",     NULL,	AddCommand,
144	"add route",			"dest mask gateway" },
145  { "close",   NULL,    CloseCommand,
146	"Close connection",		StrNull },
147  { "delete",  NULL,    DeleteCommand,
148  	"delete route",			"dest gateway" },
149  { "deny",    NULL,    DenyCommand,
150  	"Deny option request",		StrOption },
151  { "dial",    "call",  DialCommand,
152  	"Dial and login",		StrRemote },
153  { "disable", NULL,    DisableCommand,
154  	"Disable option",		StrOption },
155  { "display", NULL,    DisplayCommand,
156  	"Display option configs",	StrNull },
157  { "enable",  NULL,    EnableCommand,
158  	"Enable option",		StrOption },
159  { "load",    NULL,    LoadCommand,
160  	"Load settings",		StrRemote },
161  { "save",    NULL,    SaveCommand,
162  	"Save settings", StrNull },
163  { "set",     "setup", SetCommand,
164  	"Set parameters",  "var value" },
165  { "show",    NULL,    ShowCommand,
166  	"Show status and statictics", "var" },
167  { "term",    NULL,    TerminalCommand,
168  	"Enter to terminal mode", StrNull },
169  { "quit",    "bye",   QuitCommand,
170  	"Quit PPP program", StrNull },
171  { "help",    "?",     HelpCommand,
172	"Display this message", "[command]", (void *)Commands },
173  { NULL,      "down",  DownCommand,
174  	"Generate down event",		StrNull },
175  { NULL,      NULL,    NULL },
176};
177
178extern int ReportCcpStatus();
179extern int ReportLcpStatus();
180extern int ReportIpcpStatus();
181extern int ReportProtStatus();
182extern int ReportCompress();
183extern int ShowModemStatus();
184extern int ReportHdlcStatus();
185extern int ShowMemMap();
186
187static char *LogLevelName[] = {
188  LM_PHASE, LM_CHAT, LM_LQM,   LM_LCP,
189  LM_TCPIP, LM_HDLC, LM_ASYNC,
190};
191
192static int ShowDebugLevel()
193{
194  int i;
195
196  printf("%02x: ", loglevel);
197  for (i = LOG_PHASE; i < MAXLOGLEVEL; i++) {
198    if (loglevel & (1 << i))
199      printf("%s ", LogLevelName[i]);
200  }
201  printf("\n");
202  return(1);
203}
204
205static int ShowEscape()
206{
207  int code, bit;
208
209  if (EscMap[32]) {
210    for (code = 0; code < 32; code++) {
211      if (EscMap[code]) {
212        for (bit = 0; bit < 8; bit++) {
213          if (EscMap[code] & (1<<bit)) {
214            printf(" 0x%02x", (code << 3) + bit);
215          }
216        }
217      }
218    }
219    printf("\n");
220  }
221  return(1);
222}
223
224static int ShowTimeout()
225{
226  printf(" Idle Timer: %d secs   LQR Timer: %d secs\n",
227    VarIdleTimeout, VarLqrTimeout);
228  return(1);
229}
230
231static int ShowAuthKey()
232{
233  printf("AuthName = %s\n", VarAuthName);
234  printf("AuthKey  = %s\n", VarAuthKey);
235  return(1);
236}
237
238static int ShowVersion()
239{
240  extern char *VarVersion[];
241
242  printf("%s\n", VarVersion);
243  return(1);
244}
245
246static int ShowLogList()
247{
248  ListLog();
249  return(1);
250}
251
252extern int ShowIfilter(), ShowOfilter(), ShowDfilter();
253
254struct cmdtab ShowCommands[] = {
255  { "auth",     NULL,     ShowAuthKey,       "Show auth name/key",
256	StrNull, },
257  { "ccp",      NULL,     ReportCcpStatus,   "Show CCP status",
258	StrNull, },
259  { "compress", NULL,     ReportCompress,    "Show compression statictics",
260	StrNull },
261  { "debug",	NULL,	  ShowDebugLevel,    "Show current debug level",
262	StrNull },
263  { "dfilter",  NULL,     ShowDfilter,       "Show Demand filters",
264	StrOption },
265  { "escape",   NULL,     ShowEscape,        "Show escape characters",
266	StrNull },
267  { "hdlc",	NULL,	  ReportHdlcStatus,  "Show HDLC error summary",
268  	StrNull },
269  { "ifilter",  NULL,     ShowIfilter,       "Show Input filters",
270	StrOption },
271  { "ipcp",     NULL,     ReportIpcpStatus,  "Show IPCP status",
272	StrNull, },
273  { "lcp",      NULL,     ReportLcpStatus,   "Show LCP status",
274	StrNull, },
275  { "log",      NULL,     ShowLogList,       "Show log records",
276	StrNull, },
277  { "mem",      NULL,     ShowMemMap,        "Show memory map",
278	StrNull, },
279  { "modem",    NULL,     ShowModemStatus,   "Show modem setups",
280	StrNull, },
281  { "ofilter",  NULL,     ShowOfilter,       "Show Output filters",
282	StrOption },
283  { "proto",    NULL,     ReportProtStatus,  "Show protocol summary",
284	StrNull, },
285  { "route",    NULL,     ShowRoute,	     "Show routing table",
286	StrNull, },
287  { "timeout",  NULL,	  ShowTimeout,       "Show Idle timeout value",
288	StrNull, },
289  { "version",  NULL,	  ShowVersion,       "Show version string",
290	StrNull, },
291  { "help",     "?",      HelpCommand,       "Display this message",
292	StrNull, (void *)ShowCommands },
293  { NULL,       NULL,     NULL },
294};
295
296struct cmdtab *
297FindCommand(cmds, str, pmatch)
298struct cmdtab *cmds;
299char *str;
300int *pmatch;
301{
302  int nmatch = 0;
303  int len = strlen(str);
304  struct cmdtab *found = NULL;
305
306  while (cmds->func) {
307    if (cmds->name && strncmp(str, cmds->name, len) == 0) {
308      nmatch++;
309      found = cmds;
310    } else if (cmds->alias && strncmp(str, cmds->alias, len) == 0) {
311      nmatch++;
312      found = cmds;
313    }
314    cmds++;
315  }
316  *pmatch = nmatch;
317  return(found);
318}
319
320int
321FindExec(cmdlist, argc, argv)
322struct cmdtab *cmdlist;
323int argc;
324char **argv;
325{
326  struct cmdtab *cmd;
327  int val = 1;
328  int nmatch;
329
330  cmd = FindCommand(cmdlist, *argv, &nmatch);
331  if (nmatch > 1)
332    printf("Anbiguous.\n");
333  else if (cmd)
334    val = (cmd->func)(cmd, --argc, ++argv, cmd->args);
335  else
336    printf("what?\n");
337  return(val);
338}
339
340void
341Prompt(flag)
342int flag;
343{
344  if (!(mode & MODE_INTER))
345    return;
346  if (flag) printf("\n");
347  if (IpcpFsm.state == ST_OPENED && phase == PHASE_NETWORK)
348    printf("PPP> ");
349  else
350    printf("ppp> ");
351  fflush(stdout);
352}
353
354void
355DecodeCommand(buff, nb, prompt)
356char *buff;
357int nb;
358int prompt;
359{
360  char *vector[20];
361  char **argv;
362  int argc, val;
363  char *cp;
364
365  val = 1;
366  if (nb > 0) {
367    cp = buff + strcspn(buff, "\r\n");
368    if (cp)
369      *cp = '\0';
370    {
371      argc = MakeArgs(buff, &vector);
372      argv = vector;
373
374      if (argc > 0)
375        val = FindExec(Commands, argc, argv);
376    }
377  }
378  if (val && prompt)
379    Prompt(0);
380}
381
382static int
383ShowCommand(list, argc, argv)
384struct cmdtab *list;
385int argc;
386char **argv;
387{
388  int val = 1;
389
390  if (argc > 0)
391    val = FindExec(ShowCommands, argc, argv);
392  else
393    printf("Use ``show ?'' to get a list.\n");
394  return(val);
395}
396
397static int
398TerminalCommand()
399{
400  if (LcpFsm.state > ST_CLOSED) {
401    printf("LCP state is [%s]\n", StateNames[LcpFsm.state]);
402    return(1);
403  }
404  if (!IsInteractive())
405    return(1);
406  modem = OpenModem(mode);
407  if (modem < 0) {
408    printf("failed to open modem.\n");
409    modem = 0;
410    return(1);
411  }
412  printf("Enter to terminal mode.\n");
413  printf("Type `~?' for help.\n");
414  TtyTermMode();
415  return(0);
416}
417
418static int
419QuitCommand(list, argc, argv)
420struct cmdtab *list;
421int argc;
422char **argv;
423{
424  if (mode & (MODE_DIRECT|MODE_DEDICATED|MODE_AUTO)) {
425    if (argc > 0) {
426      Cleanup(EX_NORMAL);
427    } else {
428      close(netfd);
429      close(1);
430      netfd = -1;
431      mode &= ~MODE_INTER;
432    }
433  } else
434    Cleanup(EX_NORMAL);
435  return(1);
436}
437
438static int
439CloseCommand()
440{
441  LcpClose();
442  return(1);
443}
444
445static int
446DownCommand()
447{
448  LcpDown();
449  return(1);
450}
451
452static int validspeed[] = {
453  1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 0
454};
455
456static int SetModemSpeed(list, argc, argv)
457struct cmdtab *list;
458int argc;
459char **argv;
460{
461  int speed;
462  int *sp;
463
464  if (argc > 0) {
465    speed = atoi(*argv);
466    for (sp = validspeed; *sp; sp++) {
467      if (*sp == speed) {
468	VarSpeed = speed;
469	return(1);
470      }
471    }
472    printf("invalid speed.\n");
473  }
474  return(1);
475}
476
477static int SetModemParity(list, argc, argv)
478struct cmdtab *list;
479int argc;
480char **argv;
481{
482  int parity;
483
484  if (argc > 0) {
485    parity = ChangeParity(*argv);
486    if (parity < 0)
487      printf("Invalid parity.\n");
488    else
489      VarParity = parity;
490  }
491  return(1);
492}
493
494static int
495SetDebugLevel(list, argc, argv)
496struct cmdtab *list;
497int argc;
498char **argv;
499{
500  int level, w;
501
502  for (level = 0; argc-- > 0; argv++) {
503    if (isdigit(**argv)) {
504      w = atoi(*argv);
505      if (w < 0 || w >= MAXLOGLEVEL) {
506	printf("invalid log level.\n");
507	break;
508      } else
509	level |= (1 << w);
510    } else {
511      for (w = 0; w < MAXLOGLEVEL; w++) {
512	if (strcasecmp(*argv, LogLevelName[w]) == 0) {
513	  level |= (1 << w);
514	  continue;
515	}
516      }
517    }
518  }
519  loglevel = level;
520  return(1);
521}
522
523static int
524SetEscape(list, argc, argv)
525struct cmdtab *list;
526int argc;
527char **argv;
528{
529  int code;
530
531  for (code = 0; code < 33; code++)
532    EscMap[code] = 0;
533  while (argc-- > 0) {
534    sscanf(*argv++, "%x", &code);
535    code &= 0xff;
536    EscMap[code >> 3] |= (1 << (code&7));
537    EscMap[32] = 1;
538  }
539  return(1);
540}
541
542static int
543SetInitialMRU(list, argc, argv)
544struct cmdtab *list;
545int argc;
546char **argv;
547{
548  int mru;
549
550  if (argc > 0) {
551    mru = atoi(*argv);
552    if (mru < 100)
553      printf("given value is too small.\n");
554    else if (mru > MAX_MRU)
555      printf("given value is too big.\n");
556    else
557      VarMRU = mru;
558  }
559  return(1);
560}
561
562static int
563SetIdleTimeout(list, argc, argv)
564struct cmdtab *list;
565int argc;
566char **argv;
567{
568  if (argc-- > 0) {
569    VarIdleTimeout = atoi(*argv++);
570    if (argc > 0)
571      VarLqrTimeout = atoi(*argv);
572  }
573  return(1);
574}
575
576struct in_addr
577GetIpAddr(cp)
578char *cp;
579{
580  struct hostent *hp;
581  struct in_addr ipaddr;
582
583  hp = gethostbyname(cp);
584  if (hp && hp->h_addrtype == AF_INET)
585    bcopy(hp->h_addr, &ipaddr, hp->h_length);
586  else if (inet_aton(cp, &ipaddr) == 0)
587    ipaddr.s_addr = 0;
588  return(ipaddr);
589}
590
591static int
592SetInterfaceAddr(list, argc, argv)
593struct cmdtab *list;
594int argc;
595char **argv;
596{
597  int width;
598
599  DefMyAddress.ipaddr.s_addr = DefHisAddress.ipaddr.s_addr = 0L;
600  if (argc > 0) {
601    ParseAddr(argc, argv++,
602      &DefMyAddress.ipaddr, &DefMyAddress.mask, &DefMyAddress.width);
603    if (--argc > 0) {
604      ParseAddr(argc, argv++,
605	&DefHisAddress.ipaddr, &DefHisAddress.mask, &DefHisAddress.width);
606      if (--argc > 0) {
607        ifnetmask = GetIpAddr(*argv);
608      }
609    }
610  }
611  /*
612   * For backwards compatibility, 0.0.0.0 means any address.
613   */
614  if (DefMyAddress.ipaddr.s_addr == 0) {
615    DefMyAddress.mask.s_addr = 0;
616    DefMyAddress.width = 0;
617  }
618  if (DefHisAddress.ipaddr.s_addr == 0) {
619    DefHisAddress.mask.s_addr = 0;
620    DefHisAddress.width = 0;
621  }
622
623  if ((mode & MODE_AUTO) |
624	((mode & MODE_DEDICATED) && dstsystem)) {
625    OsSetIpaddress(DefMyAddress.ipaddr, DefHisAddress.ipaddr, ifnetmask);
626  }
627  return(1);
628}
629
630
631#define	VAR_AUTHKEY	0
632#define	VAR_DIAL	1
633#define	VAR_LOGIN	2
634#define	VAR_AUTHNAME	3
635#define	VAR_DEVICE	4
636#define	VAR_ACCMAP	5
637#define	VAR_PHONE	6
638
639static int
640SetVariable(list, argc, argv, param)
641struct cmdtab *list;
642int argc;
643char **argv;
644int param;
645{
646  u_long map;
647
648  if (argc > 0) {
649    switch (param) {
650    case VAR_AUTHKEY:
651      strncpy(VarAuthKey, *argv, sizeof(VarAuthKey)-1);
652      break;
653    case VAR_AUTHNAME:
654      strncpy(VarAuthName, *argv, sizeof(VarAuthName)-1);
655      break;
656    case VAR_DIAL:
657      strncpy(VarDialScript, *argv, sizeof(VarDialScript)-1);
658      break;
659    case VAR_LOGIN:
660      strncpy(VarLoginScript, *argv, sizeof(VarDialScript)-1);
661      break;
662    case VAR_DEVICE:
663      strncpy(VarDevice, *argv, sizeof(VarDevice)-1);
664      break;
665    case VAR_ACCMAP:
666      sscanf(*argv, "%x", &map);
667      VarAccmap = map;
668      break;
669    case VAR_PHONE:
670      strncpy(VarPhone, *argv, sizeof(VarPhone)-1);
671      break;
672    }
673  }
674  return(1);
675}
676
677static int SetOpenMode(list, argc, argv)
678struct cmdtab *list;
679int argc;
680char **argv;
681{
682  if (argc > 0) {
683    if (strcmp(*argv, "active") == 0)
684      VarOpenMode = OPEN_ACTIVE;
685    else if (strcmp(*argv, "passive") == 0)
686      VarOpenMode = OPEN_PASSIVE;
687    else
688      printf("Invalid mode.\n");
689  }
690  return(1);
691}
692
693static char StrChatStr[] = "chat-script";
694static char StrValue[] = "value";
695
696extern int SetIfilter(), SetOfilter(), SetDfilter();
697
698struct cmdtab SetCommands[] = {
699  { "accmap",   NULL,	  SetVariable,	  "Set accmap value",
700	"hex-value",	(void *)VAR_ACCMAP },
701  { "authkey",  "key",     SetVariable,	  "Set authentication key",
702	"key",		(void *)VAR_AUTHKEY },
703  { "authname", NULL,     SetVariable,    "Set authentication name",
704	"name",		(void *)VAR_AUTHNAME },
705  { "debug",    NULL,	  SetDebugLevel,  "Set debug level",
706	StrValue },
707  { "device",     "line", SetVariable, "Set modem device name",
708	"device-name",	(void *)VAR_DEVICE },
709  { "dfilter",  NULL,     SetDfilter,  "Set demand filter",
710        "..." },
711  { "dial",     NULL,     SetVariable, 	 "Set dialing script",
712	StrChatStr,	(void *)VAR_DIAL },
713  { "escape",   NULL,	  SetEscape,       "Set escape characters",
714        "hex-digit ..."},
715  { "ifaddr",   NULL,   SetInterfaceAddr,  "Set destination address",
716	"src-addr dst-addr netmask" },
717  { "ifilter",  NULL,     SetIfilter,  "Set input filter",
718        "..." },
719  { "login",    NULL,     SetVariable,	"Set login script",
720	 StrChatStr,	(void *)VAR_LOGIN },
721  { "mru",      "mtu",    SetInitialMRU,  "Set Initial MRU value",
722	StrValue },
723  { "ofilter",  NULL,	  SetOfilter,	  "Set output filter",
724        "..." },
725  { "openmode", NULL,	  SetOpenMode,	  "Set open mode",
726	"[active|passive]" },
727  { "parity",   NULL,     SetModemParity, "Set modem parity",
728	"[odd|even|none]" },
729  { "phone",    NULL,     SetVariable,	  "Set telephone number",
730        "phone-number",	(void *)VAR_PHONE },
731  { "speed",    NULL,     SetModemSpeed,  "Set modem speed",
732	"speed" },
733  { "timeout",  NULL,     SetIdleTimeout, "Set Idle timeout",
734	StrValue },
735  { "help",     "?",      HelpCommand,    "Display this message",
736	StrNull, (void *)SetCommands },
737  { NULL,       NULL,     NULL },
738};
739
740static int
741SetCommand(list, argc, argv)
742struct cmdtab *list;
743int argc;
744char **argv;
745{
746  int val = 1;
747
748  if (argc > 0)
749    val = FindExec(SetCommands, argc, argv);
750  else
751    printf("Use ``set ?'' to get a list.\n");
752  return(val);
753}
754
755
756static int
757AddCommand(list, argc, argv)
758struct cmdtab *list;
759int argc;
760char **argv;
761{
762  struct in_addr dest, gateway, netmask;
763
764  if (argc == 3) {
765    dest = GetIpAddr(argv[0]);
766    netmask = GetIpAddr(argv[1]);
767    if (strcmp(argv[2], "HISADDR") == 0)
768      gateway = IpcpInfo.his_ipaddr;
769    else
770      gateway = GetIpAddr(argv[2]);
771    OsSetRoute(RTM_ADD, dest, gateway, netmask);
772  } else {
773    printf("Usage: %s %s\n", list->name, list->syntax);
774  }
775  return(1);
776}
777
778static int
779DeleteCommand(list, argc, argv)
780struct cmdtab *list;
781int argc;
782char **argv;
783{
784  struct in_addr dest, gateway, netmask;
785
786  if (argc >= 2) {
787    dest = GetIpAddr(argv[0]);
788    if (strcmp(argv[1], "HISADDR") == 0)
789      gateway = IpcpInfo.his_ipaddr;
790    else
791      gateway = GetIpAddr(argv[1]);
792    netmask.s_addr = 0;
793    if (argc == 3) {
794      if (inet_aton(argv[1], &netmask) == 0) {
795	printf("bad netmask value.\n");
796	return(1);
797      }
798    }
799    OsSetRoute(RTM_DELETE, dest, gateway, netmask);
800  } else if (argc == 1 && strcmp(argv[0], "ALL") == 0) {
801    DeleteIfRoutes(0);
802  } else {
803    printf("Usage: %s %s\n", list->name, list->syntax);
804  }
805  return(1);
806}
807
808