main.c revision 25910
1145522Sdarrenr/*
2145522Sdarrenr *			User Process PPP
353642Sguido *
4255332Scy *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
553642Sguido *
680482Sdarrenr *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
753642Sguido *
853642Sguido * Redistribution and use in source and binary forms are permitted
957126Sguido * provided that the above copyright notice and this paragraph are
10172776Sdarrenr * duplicated in all such forms and that any documentation,
1153642Sguido * advertising materials, and other materials related to such
1253642Sguido * distribution and use acknowledge that the software was developed
1353642Sguido * by the Internet Initiative Japan, Inc.  The name of the
1453642Sguido * IIJ may not be used to endorse or promote products derived
15153876Sguido * from this software without specific prior written permission.
16145522Sdarrenr * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1760854Sdarrenr * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18145522Sdarrenr * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1960854Sdarrenr *
2060854Sdarrenr * $Id: main.c,v 1.52 1997/05/19 02:00:06 brian Exp $
21145522Sdarrenr *
22145522Sdarrenr *	TODO:
2380482Sdarrenr *		o Add commands for traffic summary, version display, etc.
2480482Sdarrenr *		o Add signal handler for misc controls.
2580482Sdarrenr */
2680482Sdarrenr#include "fsm.h"
2780482Sdarrenr#include <fcntl.h>
2880482Sdarrenr#include <paths.h>
2953642Sguido#include <sys/time.h>
30255332Scy#include <termios.h>
31255332Scy#include <signal.h>
32255332Scy#include <sys/wait.h>
33255332Scy#include <errno.h>
3453642Sguido#include <netdb.h>
3553642Sguido#include <unistd.h>
3653642Sguido#include <sys/socket.h>
37145522Sdarrenr#include <arpa/inet.h>
3853642Sguido#include <netinet/in_systm.h>
3960854Sdarrenr#include <netinet/ip.h>
4060854Sdarrenr#include "modem.h"
4160854Sdarrenr#include "os.h"
4292685Sdarrenr#include "hdlc.h"
43145522Sdarrenr#include "ccp.h"
44145522Sdarrenr#include "lcp.h"
4595418Sdarrenr#include "ipcp.h"
46145522Sdarrenr#include "vars.h"
47145522Sdarrenr#include "auth.h"
48145522Sdarrenr#include "filter.h"
49145522Sdarrenr#include "systems.h"
50145522Sdarrenr#include "ip.h"
51145522Sdarrenr#include "alias.h"
52145522Sdarrenr#include "sig.h"
53145522Sdarrenr
54145522Sdarrenr#define LAUTH_M1 "Warning: No password entry for this host in ppp.secret\n"
55145522Sdarrenr#define LAUTH_M2 "Warning: All manipulation is allowed by anyone in the world\n"
56145522Sdarrenr
57145522Sdarrenr#ifndef O_NONBLOCK
5895418Sdarrenr#ifdef O_NDELAY
5953642Sguido#define	O_NONBLOCK O_NDELAY
60145522Sdarrenr#endif
61255332Scy#endif
62145522Sdarrenr
63145522Sdarrenrextern void VjInit(), AsyncInit();
64153876Sguidoextern void AsyncInput();
65153876Sguidoextern int  SelectSystem();
6653642Sguido
6753642Sguidoextern void DecodeCommand(), Prompt();
6853642Sguidoextern int aft_cmd;
6953642Sguidoextern int IsInteractive();
7053642Sguidostatic void DoLoop(void);
71145522Sdarrenrstatic void TerminalStop();
72145522Sdarrenrstatic char *ex_desc();
73145522Sdarrenr
74145522Sdarrenrstatic struct termios oldtio;		/* Original tty mode */
7553642Sguidostatic struct termios comtio;		/* Command level tty mode */
76145522Sdarrenrint TermMode;
77145522Sdarrenrstatic int server;
78145522Sdarrenrstatic pid_t BGPid = 0;
79145522Sdarrenrstruct sockaddr_in ifsin;
80145522Sdarrenrstatic char pid_filename[MAXPATHLEN];
81255332Scystatic char if_filename[MAXPATHLEN];
82255332Scyint tunno;
83145522Sdarrenr
84145522Sdarrenrstatic void
85145522SdarrenrTtyInit()
8653642Sguido{
8753642Sguido  struct termios newtio;
88145522Sdarrenr  int stat;
89145522Sdarrenr
90145522Sdarrenr  stat = fcntl(0, F_GETFL, 0);
9160854Sdarrenr  if (stat > 0) {
9260854Sdarrenr	 stat |= O_NONBLOCK;
9360854Sdarrenr	 (void)fcntl(0, F_SETFL, stat);
94145522Sdarrenr  }
9560854Sdarrenr  newtio = oldtio;
9660854Sdarrenr  newtio.c_lflag &= ~(ECHO|ISIG|ICANON);
9760854Sdarrenr  newtio.c_iflag = 0;
9860854Sdarrenr  newtio.c_oflag &= ~OPOST;
9953642Sguido  newtio.c_cc[VEOF] = _POSIX_VDISABLE;
10053642Sguido  newtio.c_cc[VINTR] = _POSIX_VDISABLE;
10153642Sguido  newtio.c_cc[VMIN] = 1;
10253642Sguido  newtio.c_cc[VTIME] = 0;
103145522Sdarrenr  newtio.c_cflag |= CS8;
104145522Sdarrenr  tcsetattr(0, TCSADRAIN, &newtio);
105145522Sdarrenr  comtio = newtio;
106145522Sdarrenr}
10753642Sguido
10853642Sguido/*
10960854Sdarrenr *  Set tty into command mode. We allow canonical input and echo processing.
11092685Sdarrenr */
111145522Sdarrenrvoid
112145522SdarrenrTtyCommandMode(prompt)
11353642Sguidoint prompt;
114145522Sdarrenr{
115145522Sdarrenr  struct termios newtio;
116145522Sdarrenr  int stat;
117145522Sdarrenr
118145522Sdarrenr  if (!(mode & MODE_INTER))
119145522Sdarrenr    return;
120145522Sdarrenr  tcgetattr(0, &newtio);
121145522Sdarrenr  newtio.c_lflag |= (ECHO|ISIG|ICANON);
122145522Sdarrenr  newtio.c_iflag = oldtio.c_iflag;
123145522Sdarrenr  newtio.c_oflag |= OPOST;
124145522Sdarrenr  tcsetattr(0, TCSADRAIN, &newtio);
125145522Sdarrenr  stat = fcntl(0, F_GETFL, 0);
126255332Scy  if (stat > 0) {
127145522Sdarrenr	 stat |= O_NONBLOCK;
128145522Sdarrenr	 (void)fcntl(0, F_SETFL, stat);
129145522Sdarrenr  }
130145522Sdarrenr  TermMode = 0;
131145522Sdarrenr  if(prompt) Prompt();
132145522Sdarrenr}
133145522Sdarrenr
134145522Sdarrenr/*
135145522Sdarrenr * Set tty into terminal mode which is used while we invoke term command.
136145522Sdarrenr */
137145522Sdarrenrvoid
138255332ScyTtyTermMode()
139145522Sdarrenr{
140145522Sdarrenr  int stat;
141145522Sdarrenr
14253642Sguido  tcsetattr(0, TCSADRAIN, &comtio);
14353642Sguido  stat = fcntl(0, F_GETFL, 0);
14453642Sguido  if (stat > 0) {
14553642Sguido	 stat &= ~O_NONBLOCK;
14653642Sguido	 (void)fcntl(0, F_SETFL, stat);
14753642Sguido  }
14853642Sguido  TermMode = 1;
14953642Sguido}
150145522Sdarrenr
151145522Sdarrenrvoid
15253642SguidoTtyOldMode()
15353642Sguido{
15460854Sdarrenr  int stat;
15560854Sdarrenr
15660854Sdarrenr  stat = fcntl(0, F_GETFL, 0);
15760854Sdarrenr  if (stat > 0) {
15860854Sdarrenr	  stat &= ~O_NONBLOCK;
15953642Sguido	  (void)fcntl(0, F_SETFL, stat);
16060854Sdarrenr  }
16160854Sdarrenr  tcsetattr(0, TCSANOW, &oldtio);
16260854Sdarrenr}
16353642Sguido
164145522Sdarrenrvoid
165145522SdarrenrCleanup(excode)
166145522Sdarrenrint excode;
167145522Sdarrenr{
168145522Sdarrenr
16953642Sguido  OsLinkdown();
17053642Sguido  OsCloseLink(1);
17153642Sguido  sleep(1);
17253642Sguido  if (mode & MODE_AUTO)
17353642Sguido    DeleteIfRoutes(1);
17453642Sguido  (void)unlink(pid_filename);
17560854Sdarrenr  (void)unlink(if_filename);
17660854Sdarrenr  OsInterfaceDown(1);
17760854Sdarrenr  if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) {
17860854Sdarrenr    char c = EX_ERRDEAD;
179102520Sdarrenr    if (write(BGFiledes[1],&c,1) == 1)
180145522Sdarrenr      LogPrintf(LOG_PHASE_BIT,"Parent notified of failure.\n");
18153642Sguido    else
18253642Sguido      LogPrintf(LOG_PHASE_BIT,"Failed to notify parent of failure.\n");
18353642Sguido    close(BGFiledes[1]);
18453642Sguido  }
18553642Sguido  LogPrintf(LOG_PHASE_BIT, "PPP Terminated (%s).\n",ex_desc(excode));
18653642Sguido  LogClose();
187145522Sdarrenr  if (server >= 0) {
188145522Sdarrenr    close(server);
189255332Scy    server = -1;
190145522Sdarrenr  }
191145522Sdarrenr
192145522Sdarrenr  TtyOldMode();
193145522Sdarrenr
194145522Sdarrenr  exit(excode);
195145522Sdarrenr}
196170268Sdarrenr
19753642Sguidostatic void
19853642SguidoHangup(signo)
19953642Sguidoint signo;
200255332Scy{
201255332Scy  if (signo == SIGSEGV) {
202255332Scy	LogPrintf(LOG_PHASE_BIT, "Signal %d, core dump.\n", signo);
203255332Scy	LogClose();
204255332Scy	abort();
205255332Scy  }
206255332Scy  if (BGPid) {
207255332Scy      kill (BGPid, SIGTERM);
208255332Scy      exit (EX_HANGUP);
209255332Scy  }
210255332Scy  else {
211255332Scy      LogPrintf(LOG_PHASE_BIT, "Signal %d, hangup.\n", signo);
212255332Scy      Cleanup(EX_HANGUP);
213255332Scy  }
214255332Scy}
215255332Scy
216255332Scystatic void
217255332ScyCloseSession(signo)
218255332Scyint signo;
219255332Scy{
22053642Sguido   if (BGPid) {
221255332Scy     kill (BGPid, SIGINT);
222255332Scy     exit (EX_TERM);
223255332Scy   }
224255332Scy   else {
225255332Scy     LogPrintf(LOG_PHASE_BIT, "Signal %d, terminate.\n", signo);
226255332Scy     LcpClose();
227255332Scy     reconnectCount = 0;
228255332Scy     Cleanup(EX_TERM);
229255332Scy   }
230255332Scy}
231255332Scy
232255332Scystatic void
233255332ScyTerminalCont()
234255332Scy{
235255332Scy  pending_signal(SIGCONT, SIG_DFL);
236255332Scy  pending_signal(SIGTSTP, TerminalStop);
237255332Scy  TtyCommandMode(getpgrp() == tcgetpgrp(0));
238255332Scy}
239255332Scy
240255332Scystatic void
24153642SguidoTerminalStop(signo)
242255332Scyint signo;
243255332Scy{
244255332Scy  pending_signal(SIGCONT, TerminalCont);
24553642Sguido  TtyOldMode();
246255332Scy  pending_signal(SIGTSTP, SIG_DFL);
247255332Scy  kill(getpid(), signo);
248255332Scy}
249255332Scy
250255332Scystatic char *
251255332Scyex_desc(int ex)
252255332Scy{
25353642Sguido  static char num[12];
254255332Scy  static char *desc[] = { "normal", "start", "sock",
255255332Scy    "modem", "dial", "dead", "done", "reboot", "errdead",
256255332Scy    "hangup", "term", "nodial", "nologin" };
257255332Scy
258255332Scy  if (ex >= 0 && ex < sizeof(desc)/sizeof(*desc))
259255332Scy    return desc[ex];
260255332Scy  snprintf(num, sizeof num, "%d", ex);
261170268Sdarrenr  return num;
262255332Scy}
263255332Scy
264255332Scyvoid
265255332ScyUsage()
26653642Sguido{
26753642Sguido  fprintf(stderr,
26853642Sguido          "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ] [ -alias ] [system]\n");
269255332Scy  exit(EX_START);
270255332Scy}
271255332Scy
272255332Scyvoid
273255332ScyProcessArgs(int argc, char **argv)
274255332Scy{
275255332Scy  int optc;
276255332Scy  char *cp;
277255332Scy
278255332Scy  optc = 0;
279255332Scy  while (argc > 0 && **argv == '-') {
280255332Scy    cp = *argv + 1;
281255332Scy    if (strcmp(cp, "auto") == 0)
282255332Scy      mode |= MODE_AUTO;
283255332Scy    else if (strcmp(cp, "background") == 0)
284255332Scy      mode |= MODE_BACKGROUND|MODE_AUTO;
285255332Scy    else if (strcmp(cp, "direct") == 0)
286255332Scy      mode |= MODE_DIRECT;
287255332Scy    else if (strcmp(cp, "dedicated") == 0)
288255332Scy      mode |= MODE_DEDICATED;
289255332Scy    else if (strcmp(cp, "ddial") == 0)
290255332Scy      mode |= MODE_DDIAL|MODE_AUTO;
291255332Scy    else if (strcmp(cp, "alias") == 0) {
292255332Scy      mode |= MODE_ALIAS;
293255332Scy      optc--;             /* this option isn't exclusive */
294255332Scy    }
295255332Scy    else
296255332Scy      Usage();
297145522Sdarrenr    optc++;
298255332Scy    argv++; argc--;
299255332Scy  }
300255332Scy  if (argc > 1) {
301255332Scy    fprintf(stderr, "specify only one system label.\n");
302255332Scy    exit(EX_START);
303255332Scy  }
304255332Scy  if (argc == 1) dstsystem = *argv;
305145522Sdarrenr
30653642Sguido  if (optc > 1) {
307255332Scy    fprintf(stderr, "specify only one mode.\n");
308255332Scy    exit(EX_START);
309255332Scy  }
310255332Scy}
311255332Scy
312255332Scystatic void
313255332ScyGreetings()
314255332Scy{
315255332Scy  printf("User Process PPP. Written by Toshiharu OHNO.\r\n");
316255332Scy  fflush(stdout);
317255332Scy}
318255332Scy
319255332Scyvoid
320255332Scymain(argc, argv)
321255332Scyint argc;
322255332Scychar **argv;
323255332Scy{
324255332Scy  FILE *lockfile;
325255332Scy  argc--; argv++;
326255332Scy
327255332Scy  mode = MODE_INTER;		/* default operation is interactive mode */
328255332Scy  netfd = server = modem = tun_in = -1;
329255332Scy  ProcessArgs(argc, argv);
330255332Scy  Greetings();
331255332Scy  GetUid();
332255332Scy  IpcpDefAddress();
333255332Scy  InitAlias();
334255332Scy
335255332Scy  if (SelectSystem("default", CONFFILE) < 0) {
336255332Scy    fprintf(stderr, "Warning: No default entry is given in config file.\n");
33753642Sguido  }
338
339  switch ( LocalAuthInit() ) {
340    case NOT_FOUND:
341    	fprintf(stderr,LAUTH_M1);
342    	fprintf(stderr,LAUTH_M2);
343	fflush (stderr);
344	/* Fall down */
345    case VALID:
346	VarLocalAuth = LOCAL_AUTH;
347	break;
348    default:
349	break;
350  }
351
352  if (OpenTunnel(&tunno) < 0) {
353    perror("open_tun");
354    exit(EX_START);
355  }
356
357  if (mode & (MODE_AUTO|MODE_DIRECT|MODE_DEDICATED))
358    mode &= ~MODE_INTER;
359  if (mode & MODE_INTER) {
360    printf("Interactive mode\n");
361    netfd = STDIN_FILENO;
362  } else if (mode & MODE_AUTO) {
363    printf("Automatic Dialer mode\n");
364    if (dstsystem == NULL) {
365      fprintf(stderr, "Destination system must be specified in"
366              " auto, background or ddial mode.\n");
367      exit(EX_START);
368    }
369  }
370
371  tcgetattr(0, &oldtio);		/* Save original tty mode */
372
373  pending_signal(SIGHUP, LogReOpen);
374  pending_signal(SIGTERM, CloseSession);
375  pending_signal(SIGINT, CloseSession);
376  pending_signal(SIGQUIT, CloseSession);
377#ifdef SIGSEGV
378  signal(SIGSEGV, Hangup);
379#endif
380#ifdef SIGPIPE
381  signal(SIGPIPE, SIG_IGN);
382#endif
383#ifdef SIGALRM
384  pending_signal(SIGALRM, SIG_IGN);
385#endif
386  if(mode & MODE_INTER)
387    {
388#ifdef SIGTSTP
389      pending_signal(SIGTSTP, TerminalStop);
390#endif
391#ifdef SIGTTIN
392      pending_signal(SIGTTIN, TerminalStop);
393#endif
394#ifdef SIGTTOU
395      pending_signal(SIGTTOU, SIG_IGN);
396#endif
397    }
398
399  if (dstsystem) {
400    if (SelectSystem(dstsystem, CONFFILE) < 0) {
401      fprintf(stderr, "Destination system not found in conf file.\n");
402      Cleanup(EX_START);
403    }
404    if ((mode & MODE_AUTO) && DefHisAddress.ipaddr.s_addr == INADDR_ANY) {
405      fprintf(stderr, "Must specify dstaddr with"
406              " auto, background or ddial mode.\n");
407      Cleanup(EX_START);
408    }
409  }
410  if (mode & MODE_DIRECT)
411    printf("Packet mode enabled.\n");
412
413  if (!(mode & MODE_INTER)) {
414    int port = SERVER_PORT + tunno;
415
416    if (mode & MODE_BACKGROUND) {
417      if (pipe (BGFiledes)) {
418	perror("pipe");
419	Cleanup(EX_SOCK);
420      }
421    }
422
423    /* Create server socket and listen at there. */
424    server = socket(PF_INET, SOCK_STREAM, 0);
425    if (server < 0) {
426      perror("socket");
427      Cleanup(EX_SOCK);
428    }
429    ifsin.sin_family = AF_INET;
430    ifsin.sin_addr.s_addr = INADDR_ANY;
431    ifsin.sin_port = htons(port);
432    if (bind(server, (struct sockaddr *) &ifsin, sizeof(ifsin)) < 0) {
433      perror("bind");
434      if (errno == EADDRINUSE)
435        fprintf(stderr, "Wait for a while, then try again.\n");
436      Cleanup(EX_SOCK);
437    }
438    if (listen(server, 5) != 0) {
439      fprintf(stderr, "Unable to listen to socket - OS overload?\n");
440    }
441
442    DupLog();
443    if (!(mode & MODE_DIRECT)) {
444      pid_t bgpid;
445
446      bgpid = fork ();
447      if (bgpid == -1) {
448	perror ("fork");
449	Cleanup (EX_SOCK);
450      }
451      if (bgpid) {
452	char c = EX_NORMAL;
453
454	if (mode & MODE_BACKGROUND) {
455	  /* Wait for our child to close its pipe before we exit. */
456	  BGPid = bgpid;
457          close (BGFiledes[1]);
458	  if (read(BGFiledes[0], &c, 1) != 1) {
459	    printf("Child exit, no status.\n");
460	    LogPrintf (LOG_PHASE_BIT, "Parent: Child exit, no status.\n");
461	  } else if (c == EX_NORMAL) {
462	    printf("PPP enabled.\n");
463	    LogPrintf (LOG_PHASE_BIT, "Parent: PPP enabled.\n");
464	  } else {
465	    printf("Child failed (%s).\n",ex_desc((int)c));
466	    LogPrintf(LOG_PHASE_BIT, "Parent: Child failed (%s).\n",
467                      ex_desc((int)c));
468          }
469          close (BGFiledes[0]);
470	}
471        exit(c);
472      } else if (mode & MODE_BACKGROUND)
473          close(BGFiledes[0]);
474    }
475
476    snprintf(pid_filename, sizeof (pid_filename), "%stun%d.pid",
477             _PATH_VARRUN, tunno);
478    (void)unlink(pid_filename);
479
480    if ((lockfile = fopen(pid_filename, "w")) != NULL) {
481      fprintf(lockfile, "%d\n", (int)getpid());
482      fclose(lockfile);
483    } else
484      logprintf("Warning: Can't create %s: %s\n", pid_filename, strerror(errno));
485
486    snprintf(if_filename, sizeof if_filename, "%s%s.if",
487             _PATH_VARRUN, VarBaseDevice);
488    (void)unlink(if_filename);
489
490    if ((lockfile = fopen(if_filename, "w")) != NULL) {
491      fprintf(lockfile, "tun%d\n", tunno);
492      fclose(lockfile);
493    } else
494      logprintf("Warning: Can't create %s: %s\n", if_filename, strerror(errno));
495
496    if (server >= 0)
497	LogPrintf(LOG_PHASE_BIT, "Listening at %d.\n", port);
498#ifdef DOTTYINIT
499    if (mode & (MODE_DIRECT|MODE_DEDICATED)) { /* } */
500#else
501    if (mode & MODE_DIRECT) {
502#endif
503      TtyInit();
504    } else {
505      int fd;
506
507      setsid();			/* detach control tty */
508      if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
509	(void)dup2(fd, STDIN_FILENO);
510	(void)dup2(fd, STDOUT_FILENO);
511	(void)dup2(fd, STDERR_FILENO);
512	if (fd > 2)
513		(void)close (fd);
514      }
515    }
516  } else {
517    TtyInit();
518    TtyCommandMode(1);
519  }
520  LogPrintf(LOG_PHASE_BIT, "PPP Started.\n");
521
522
523  do
524   DoLoop();
525  while (mode & MODE_DEDICATED);
526
527  Cleanup(EX_DONE);
528}
529
530/*
531 *  Turn into packet mode, where we speak PPP.
532 */
533void
534PacketMode()
535{
536  if (RawModem(modem) < 0) {
537    fprintf(stderr, "Not connected.\r\n");
538    return;
539  }
540
541  AsyncInit();
542  VjInit();
543  LcpInit();
544  IpcpInit();
545  CcpInit();
546  LcpUp();
547
548  LcpOpen(VarOpenMode);
549  if ((mode & (MODE_INTER|MODE_AUTO)) == MODE_INTER) {
550    TtyCommandMode(1);
551    fprintf(stderr, "Packet mode.\r\n");
552    aft_cmd = 1;
553  }
554}
555
556static void
557ShowHelp()
558{
559  fprintf(stderr, "The following commands are available:\r\n");
560  fprintf(stderr, " ~p\tEnter to Packet mode\r\n");
561  fprintf(stderr, " ~-\tDecrease log level\r\n");
562  fprintf(stderr, " ~+\tIncrease log level\r\n");
563  fprintf(stderr, " ~.\tTerminate program\r\n");
564  fprintf(stderr, " ~?\tThis help\r\n");
565}
566
567static void
568ReadTty()
569{
570  int n;
571  char ch;
572  static int ttystate;
573#define MAXLINESIZE 200
574  char linebuff[MAXLINESIZE];
575
576#ifdef DEBUG
577  logprintf("termode = %d, netfd = %d, mode = %d\n", TermMode, netfd, mode);
578#endif
579  if (!TermMode) {
580    n = read(netfd, linebuff, sizeof(linebuff)-1);
581    aft_cmd = 1;
582    if (n > 0) {
583      DecodeCommand(linebuff, n, 1);
584    } else {
585      LogPrintf(LOG_PHASE_BIT, "client connection closed.\n");
586      VarLocalAuth = LOCAL_NO_AUTH;
587      close(netfd);
588      close(1);
589      dup2(2, 1);     /* Have to have something here or the modem will be 1 */
590      netfd = -1;
591      mode &= ~MODE_INTER;
592    }
593    return;
594  }
595
596  /*
597   *  We are in terminal mode, decode special sequences
598   */
599  n = read(0, &ch, 1);
600#ifdef DEBUG
601  logprintf("got %d bytes\n", n);
602#endif
603
604  if (n > 0) {
605    switch (ttystate) {
606    case 0:
607      if (ch == '~')
608	ttystate++;
609      else
610	write(modem, &ch, n);
611      break;
612    case 1:
613      switch (ch) {
614      case '?':
615	ShowHelp();
616	break;
617      case '-':
618	if (loglevel > 0) {
619	  loglevel--;
620	  fprintf(stderr, "New loglevel is %d\r\n", loglevel);
621	}
622	break;
623      case '+':
624	loglevel++;
625	fprintf(stderr, "New loglevel is %d\r\n", loglevel);
626	break;
627#ifdef DEBUG
628      case 'm':
629	ShowMemMap();
630	break;
631#endif
632      case 'p':
633	/*
634	 * XXX: Should check carrier.
635	 */
636	if (LcpFsm.state <= ST_CLOSED) {
637	  VarOpenMode = OPEN_ACTIVE;
638	  PacketMode();
639	}
640	break;
641#ifdef DEBUG
642      case 't':
643	ShowTimers();
644	break;
645#endif
646      case '.':
647	TermMode = 1;
648	TtyCommandMode(1);
649	break;
650      default:
651	if (write(modem, &ch, n) < 0)
652	  fprintf(stderr, "err in write.\r\n");
653	break;
654      }
655      ttystate = 0;
656      break;
657    }
658  }
659}
660
661
662/*
663 *  Here, we'll try to detect HDLC frame
664 */
665
666static char *FrameHeaders[] = {
667  "\176\377\003\300\041",
668  "\176\377\175\043\300\041",
669  "\176\177\175\043\100\041",
670  "\176\175\337\175\043\300\041",
671  "\176\175\137\175\043\100\041",
672  NULL,
673};
674
675u_char *
676HdlcDetect(cp, n)
677u_char *cp;
678int n;
679{
680  char *ptr, *fp, **hp;
681
682  cp[n] = '\0';	/* be sure to null terminated */
683  ptr = NULL;
684  for (hp = FrameHeaders; *hp; hp++) {
685    fp = *hp;
686    if (DEV_IS_SYNC)
687      fp++;
688    ptr = strstr((char *)cp, fp);
689    if (ptr)
690      break;
691  }
692  return((u_char *)ptr);
693}
694
695static struct pppTimer RedialTimer;
696
697static void
698RedialTimeout()
699{
700  StopTimer(&RedialTimer);
701  LogPrintf(LOG_PHASE_BIT, "Redialing timer expired.\n");
702}
703
704static void
705StartRedialTimer(Timeout)
706	int Timeout;
707{
708  StopTimer(&RedialTimer);
709
710  if (Timeout) {
711    RedialTimer.state = TIMER_STOPPED;
712
713    if (Timeout > 0)
714	RedialTimer.load = Timeout * SECTICKS;
715    else
716	RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS;
717
718    LogPrintf(LOG_PHASE_BIT, "Enter pause (%d) for redialing.\n",
719	      RedialTimer.load / SECTICKS);
720
721    RedialTimer.func = RedialTimeout;
722    StartTimer(&RedialTimer);
723  }
724}
725
726
727static void
728DoLoop()
729{
730  fd_set rfds, wfds, efds;
731  int pri, i, n, wfd, nfds;
732  struct sockaddr_in hisaddr;
733  struct timeval timeout, *tp;
734  int ssize = sizeof(hisaddr);
735  u_char *cp;
736  u_char rbuff[MAX_MRU];
737  int dial_up;
738  int tries;
739  int qlen;
740  pid_t pgroup;
741
742  pgroup = getpgrp();
743
744  if (mode & MODE_DIRECT) {
745    modem = OpenModem(mode);
746    LogPrintf(LOG_PHASE_BIT, "Packet mode enabled\n");
747    fflush(stderr);
748    PacketMode();
749  } else if (mode & MODE_DEDICATED) {
750    if (modem < 0)
751      modem = OpenModem(mode);
752  }
753
754  fflush(stdout);
755
756  timeout.tv_sec = 0;
757  timeout.tv_usec = 0;
758  reconnectRequired = 0;
759
760  if (mode & MODE_BACKGROUND)
761    dial_up = TRUE;			/* Bring the line up */
762  else
763    dial_up = FALSE;			/* XXXX */
764  tries = 0;
765  for (;;) {
766    nfds = 0;
767    FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds);
768
769    /*
770     * If the link is down and we're in DDIAL mode, bring it back
771     * up.
772     */
773    if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED)
774        dial_up = TRUE;
775
776    /*
777     * If we lost carrier and want to re-establish the connection
778     * due to the "set reconnect" value, we'd better bring the line
779     * back up.
780     */
781    if (LcpFsm.state <= ST_CLOSED) {
782      if (dial_up != TRUE && reconnectRequired) {
783        if (++reconnectCount <= VarReconnectTries) {
784          LogPrintf(LOG_PHASE_BIT, "Connection lost, re-establish (%d/%d)\n",
785                    reconnectCount, VarReconnectTries);
786	  StartRedialTimer(VarReconnectTimer);
787          dial_up = TRUE;
788        } else {
789          if (VarReconnectTries)
790            LogPrintf(LOG_PHASE_BIT, "Connection lost, maximum (%d) times\n",
791                      VarReconnectTries);
792          reconnectCount = 0;
793          if (mode & MODE_BACKGROUND)
794            Cleanup(EX_DEAD);
795        }
796      }
797      reconnectRequired = 0;
798    }
799
800   /*
801    * If Ip packet for output is enqueued and require dial up,
802    * Just do it!
803    */
804    if ( dial_up && RedialTimer.state != TIMER_RUNNING ) {
805#ifdef DEBUG
806      logprintf("going to dial: modem = %d\n", modem);
807#endif
808      modem = OpenModem(mode);
809      if (modem < 0) {
810	StartRedialTimer(VarRedialTimeout);
811      } else {
812	tries++;    /* Tries are per number, not per list of numbers. */
813        if (VarDialTries)
814	  LogPrintf(LOG_CHAT_BIT, "Dial attempt %u of %d\n", tries,
815		    VarDialTries);
816        else
817	  LogPrintf(LOG_CHAT_BIT, "Dial attempt %u\n", tries);
818	if (DialModem()) {
819	  sleep(1);	       /* little pause to allow peer starts */
820	  ModemTimeout();
821	  PacketMode();
822	  dial_up = FALSE;
823	  tries = 0;
824	} else {
825	  CloseModem();
826	  if (mode & MODE_BACKGROUND) {
827	    if (VarNextPhone == NULL)
828	      Cleanup(EX_DIAL);  /* Tried all numbers - no luck */
829	    else
830	      /* Try all numbers in background mode */
831	      StartRedialTimer(VarRedialNextTimeout);
832	  } else if (VarDialTries && tries >= VarDialTries) {
833	    /* I give up !  Can't get through :( */
834	    StartRedialTimer(VarRedialTimeout);
835	    dial_up = FALSE;
836	    tries = 0;
837	  } else if (VarNextPhone == NULL)
838	    /* Dial failed. Keep quite during redial wait period. */
839	    StartRedialTimer(VarRedialTimeout);
840	  else
841	    StartRedialTimer(VarRedialNextTimeout);
842	}
843      }
844    }
845    qlen = ModemQlen();
846
847    if (qlen == 0) {
848      IpStartOutput();
849      qlen = ModemQlen();
850    }
851
852    if (modem >= 0) {
853      if (modem + 1 > nfds)
854	nfds = modem + 1;
855      FD_SET(modem, &rfds);
856      FD_SET(modem, &efds);
857      if (qlen > 0) {
858	FD_SET(modem, &wfds);
859      }
860    }
861    if (server >= 0) {
862      if (server + 1 > nfds)
863	nfds = server + 1;
864      FD_SET(server, &rfds);
865    }
866
867    /*  *** IMPORTANT ***
868     *
869     *  CPU is serviced every TICKUNIT micro seconds.
870     *	This value must be chosen with great care. If this values is
871     *  too big, it results loss of characters from modem and poor responce.
872     *  If this values is too small, ppp process eats many CPU time.
873     */
874#ifndef SIGALRM
875    usleep(TICKUNIT);
876    TimerService();
877#else
878    handle_signals();
879#endif
880
881    /* If there are aren't many packets queued, look for some more. */
882    if (qlen < 20 && tun_in >= 0) {
883      if (tun_in + 1 > nfds)
884	nfds = tun_in + 1;
885      FD_SET(tun_in, &rfds);
886    }
887
888    if (netfd >= 0) {
889      if (netfd + 1 > nfds)
890	nfds = netfd + 1;
891      FD_SET(netfd, &rfds);
892      FD_SET(netfd, &efds);
893    }
894
895#ifndef SIGALRM
896    /*
897     *  Normally, select() will not block because modem is writable.
898     *  In AUTO mode, select will block until we find packet from tun
899     */
900    tp = (RedialTimer.state == TIMER_RUNNING)? &timeout : NULL;
901    i = select(nfds, &rfds, &wfds, &efds, tp);
902#else
903    /*
904     * When SIGALRM timer is running, a select function will be
905     * return -1 and EINTR after a Time Service signal hundler
906     * is done.  If the redial timer is not running and we are
907     * trying to dial, poll with a 0 value timer.
908     */
909    tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL;
910    i = select(nfds, &rfds, &wfds, &efds, tp);
911#endif
912
913    if ( i == 0 ) {
914        continue;
915    }
916
917    if ( i < 0 ) {
918       if ( errno == EINTR ) {
919          handle_signals();
920          continue;
921       }
922       perror("select");
923       break;
924    }
925
926    if ((netfd >= 0 && FD_ISSET(netfd, &efds)) || (modem >= 0 && FD_ISSET(modem, &efds))) {
927      logprintf("Exception detected.\n");
928      break;
929    }
930
931    if (server >= 0 && FD_ISSET(server, &rfds)) {
932      LogPrintf(LOG_PHASE_BIT, "connected to client.\n");
933      wfd = accept(server, (struct sockaddr *)&hisaddr, &ssize);
934      if (wfd < 0) {
935	perror("accept");
936	continue;
937      }
938      if (netfd >= 0) {
939	write(wfd, "already in use.\n", 16);
940	close(wfd);
941	continue;
942      } else
943	netfd = wfd;
944      if (dup2(netfd, 1) < 0) {
945	perror("dup2");
946	close(netfd);
947	netfd = -1;
948	continue;
949      }
950      mode |= MODE_INTER;
951      Greetings();
952      switch ( LocalAuthInit() ) {
953         case NOT_FOUND:
954    	    fprintf(stdout,LAUTH_M1);
955    	    fprintf(stdout,LAUTH_M2);
956            fflush(stdout);
957	    /* Fall down */
958         case VALID:
959	    VarLocalAuth = LOCAL_AUTH;
960	    break;
961         default:
962	    break;
963      }
964      (void) IsInteractive();
965      Prompt();
966    }
967
968    if ((mode & MODE_INTER) && (netfd >= 0 && FD_ISSET(netfd, &rfds)) &&
969	((mode & MODE_AUTO) || pgroup == tcgetpgrp(0))) {
970      /* something to read from tty */
971      ReadTty();
972    }
973    if (modem >= 0) {
974      if (FD_ISSET(modem, &wfds)) {	/* ready to write into modem */
975	 ModemStartOutput(modem);
976      }
977      if (FD_ISSET(modem, &rfds)) {	/* something to read from modem */
978	if (LcpFsm.state <= ST_CLOSED)
979	  usleep(10000);
980	n = read(modem, rbuff, sizeof(rbuff));
981	if ((mode & MODE_DIRECT) && n <= 0) {
982	  DownConnection();
983	} else
984          LogDumpBuff(LOG_ASYNC, "ReadFromModem", rbuff, n);
985
986	if (LcpFsm.state <= ST_CLOSED) {
987	  /*
988	   *  In dedicated mode, we just discard input until LCP is started.
989	   */
990	  if (!(mode & MODE_DEDICATED)) {
991	    cp = HdlcDetect(rbuff, n);
992	    if (cp) {
993	      /*
994	       * LCP packet is detected. Turn ourselves into packet mode.
995	       */
996	      if (cp != rbuff) {
997	        write(1, rbuff, cp - rbuff);
998	        write(1, "\r\n", 2);
999	      }
1000	      PacketMode();
1001	    } else
1002	      write(1, rbuff, n);
1003	  }
1004	} else {
1005	  if (n > 0)
1006	    AsyncInput(rbuff, n);
1007	}
1008      }
1009    }
1010
1011    if (tun_in >= 0 && FD_ISSET(tun_in, &rfds)) {       /* something to read from tun */
1012      n = read(tun_in, rbuff, sizeof(rbuff));
1013      if (n < 0) {
1014	perror("read from tun");
1015	continue;
1016      }
1017      /*
1018       *  Process on-demand dialup. Output packets are queued within tunnel
1019       *  device until IPCP is opened.
1020       */
1021      if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) {
1022	pri = PacketCheck(rbuff, n, FL_DIAL);
1023	if (pri >= 0) {
1024	  if (mode & MODE_ALIAS) {
1025	    PacketAliasOut((struct ip *)rbuff);
1026	    n = ntohs(((struct ip *)rbuff)->ip_len);
1027	  }
1028	  IpEnqueue(pri, rbuff, n);
1029	  dial_up = TRUE;		/* XXX */
1030	}
1031	continue;
1032      }
1033      pri = PacketCheck(rbuff, n, FL_OUT);
1034      if (pri >= 0) {
1035        if (mode & MODE_ALIAS) {
1036          PacketAliasOut((struct ip *)rbuff);
1037          n = ntohs(((struct ip *)rbuff)->ip_len);
1038        }
1039	IpEnqueue(pri, rbuff, n);
1040      }
1041    }
1042  }
1043  logprintf("job done.\n");
1044}
1045