main.c revision 26142
1/*
2 *			User Process PPP
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: main.c,v 1.56 1997/05/24 17:32:40 brian Exp $
21 *
22 *	TODO:
23 *		o Add commands for traffic summary, version display, etc.
24 *		o Add signal handler for misc controls.
25 */
26#include "fsm.h"
27#include <fcntl.h>
28#include <paths.h>
29#include <sys/time.h>
30#include <termios.h>
31#include <signal.h>
32#include <sys/wait.h>
33#include <errno.h>
34#include <netdb.h>
35#include <unistd.h>
36#include <sys/socket.h>
37#include <arpa/inet.h>
38#include <netinet/in_systm.h>
39#include <netinet/ip.h>
40#include "modem.h"
41#include "os.h"
42#include "hdlc.h"
43#include "ccp.h"
44#include "lcp.h"
45#include "ipcp.h"
46#include "loadalias.h"
47#include "vars.h"
48#include "auth.h"
49#include "filter.h"
50#include "systems.h"
51#include "ip.h"
52#include "sig.h"
53
54#define LAUTH_M1 "Warning: No password entry for this host in ppp.secret\n"
55#define LAUTH_M2 "Warning: All manipulation is allowed by anyone in the world\n"
56
57#ifndef O_NONBLOCK
58#ifdef O_NDELAY
59#define	O_NONBLOCK O_NDELAY
60#endif
61#endif
62
63extern void VjInit(), AsyncInit();
64extern void AsyncInput();
65extern int  SelectSystem();
66
67extern void DecodeCommand(), Prompt();
68extern int aft_cmd;
69extern int IsInteractive();
70static void DoLoop(void);
71static void TerminalStop();
72static char *ex_desc();
73
74static struct termios oldtio;		/* Original tty mode */
75static struct termios comtio;		/* Command level tty mode */
76int TermMode;
77static int server;
78static pid_t BGPid = 0;
79struct sockaddr_in ifsin;
80static char pid_filename[MAXPATHLEN];
81static char if_filename[MAXPATHLEN];
82int tunno;
83
84static void
85TtyInit()
86{
87  struct termios newtio;
88  int stat;
89
90  stat = fcntl(0, F_GETFL, 0);
91  if (stat > 0) {
92	 stat |= O_NONBLOCK;
93	 (void)fcntl(0, F_SETFL, stat);
94  }
95  newtio = oldtio;
96  newtio.c_lflag &= ~(ECHO|ISIG|ICANON);
97  newtio.c_iflag = 0;
98  newtio.c_oflag &= ~OPOST;
99  newtio.c_cc[VEOF] = _POSIX_VDISABLE;
100  newtio.c_cc[VINTR] = _POSIX_VDISABLE;
101  newtio.c_cc[VMIN] = 1;
102  newtio.c_cc[VTIME] = 0;
103  newtio.c_cflag |= CS8;
104  tcsetattr(0, TCSADRAIN, &newtio);
105  comtio = newtio;
106}
107
108/*
109 *  Set tty into command mode. We allow canonical input and echo processing.
110 */
111void
112TtyCommandMode(prompt)
113int prompt;
114{
115  struct termios newtio;
116  int stat;
117
118  if (!(mode & MODE_INTER))
119    return;
120  tcgetattr(0, &newtio);
121  newtio.c_lflag |= (ECHO|ISIG|ICANON);
122  newtio.c_iflag = oldtio.c_iflag;
123  newtio.c_oflag |= OPOST;
124  tcsetattr(0, TCSADRAIN, &newtio);
125  stat = fcntl(0, F_GETFL, 0);
126  if (stat > 0) {
127	 stat |= O_NONBLOCK;
128	 (void)fcntl(0, F_SETFL, stat);
129  }
130  TermMode = 0;
131  if(prompt) Prompt();
132}
133
134/*
135 * Set tty into terminal mode which is used while we invoke term command.
136 */
137void
138TtyTermMode()
139{
140  int stat;
141
142  tcsetattr(0, TCSADRAIN, &comtio);
143  stat = fcntl(0, F_GETFL, 0);
144  if (stat > 0) {
145	 stat &= ~O_NONBLOCK;
146	 (void)fcntl(0, F_SETFL, stat);
147  }
148  TermMode = 1;
149}
150
151void
152TtyOldMode()
153{
154  int stat;
155
156  stat = fcntl(0, F_GETFL, 0);
157  if (stat > 0) {
158	  stat &= ~O_NONBLOCK;
159	  (void)fcntl(0, F_SETFL, stat);
160  }
161  tcsetattr(0, TCSANOW, &oldtio);
162}
163
164void
165Cleanup(excode)
166int excode;
167{
168
169  OsLinkdown();
170  OsCloseLink(1);
171  sleep(1);
172  if (mode & MODE_AUTO)
173    DeleteIfRoutes(1);
174  (void)unlink(pid_filename);
175  (void)unlink(if_filename);
176  OsInterfaceDown(1);
177  if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) {
178    char c = EX_ERRDEAD;
179    if (write(BGFiledes[1],&c,1) == 1)
180      LogPrintf(LOG_PHASE_BIT,"Parent notified of failure.\n");
181    else
182      LogPrintf(LOG_PHASE_BIT,"Failed to notify parent of failure.\n");
183    close(BGFiledes[1]);
184  }
185  LogPrintf(LOG_PHASE_BIT, "PPP Terminated (%s).\n",ex_desc(excode));
186  LogClose();
187  if (server >= 0) {
188    close(server);
189    server = -1;
190  }
191
192  TtyOldMode();
193
194  exit(excode);
195}
196
197static void
198Hangup(signo)
199int signo;
200{
201  if (signo == SIGSEGV) {
202	LogPrintf(LOG_PHASE_BIT, "Signal %d, core dump.\n", signo);
203	LogClose();
204	abort();
205  }
206  if (BGPid) {
207      kill (BGPid, SIGTERM);
208      exit (EX_HANGUP);
209  }
210  else {
211      LogPrintf(LOG_PHASE_BIT, "Signal %d, hangup.\n", signo);
212      Cleanup(EX_HANGUP);
213  }
214}
215
216static void
217CloseSession(signo)
218int signo;
219{
220   if (BGPid) {
221     kill (BGPid, SIGINT);
222     exit (EX_TERM);
223   }
224   else {
225     LogPrintf(LOG_PHASE_BIT, "Signal %d, terminate.\n", signo);
226     reconnect(RECON_FALSE);
227     LcpClose();
228     Cleanup(EX_TERM);
229   }
230}
231
232static void
233TerminalCont()
234{
235  pending_signal(SIGCONT, SIG_DFL);
236  pending_signal(SIGTSTP, TerminalStop);
237  TtyCommandMode(getpgrp() == tcgetpgrp(0));
238}
239
240static void
241TerminalStop(signo)
242int signo;
243{
244  pending_signal(SIGCONT, TerminalCont);
245  TtyOldMode();
246  pending_signal(SIGTSTP, SIG_DFL);
247  kill(getpid(), signo);
248}
249
250static char *
251ex_desc(int ex)
252{
253  static char num[12];
254  static char *desc[] = { "normal", "start", "sock",
255    "modem", "dial", "dead", "done", "reboot", "errdead",
256    "hangup", "term", "nodial", "nologin" };
257
258  if (ex >= 0 && ex < sizeof(desc)/sizeof(*desc))
259    return desc[ex];
260  snprintf(num, sizeof num, "%d", ex);
261  return num;
262}
263
264void
265Usage()
266{
267  fprintf(stderr,
268          "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ] [ -alias ] [system]\n");
269  exit(EX_START);
270}
271
272void
273ProcessArgs(int argc, char **argv)
274{
275  int optc;
276  char *cp;
277
278  optc = 0;
279  while (argc > 0 && **argv == '-') {
280    cp = *argv + 1;
281    if (strcmp(cp, "auto") == 0)
282      mode |= MODE_AUTO;
283    else if (strcmp(cp, "background") == 0)
284      mode |= MODE_BACKGROUND|MODE_AUTO;
285    else if (strcmp(cp, "direct") == 0)
286      mode |= MODE_DIRECT;
287    else if (strcmp(cp, "dedicated") == 0)
288      mode |= MODE_DEDICATED;
289    else if (strcmp(cp, "ddial") == 0)
290      mode |= MODE_DDIAL|MODE_AUTO;
291    else if (strcmp(cp, "alias") == 0) {
292      if (loadAliasHandlers(&VarAliasHandlers) == 0)
293        mode |= MODE_ALIAS;
294      else
295        printf("Cannot load alias library\n");
296      optc--;             /* this option isn't exclusive */
297    }
298    else
299      Usage();
300    optc++;
301    argv++; argc--;
302  }
303  if (argc > 1) {
304    fprintf(stderr, "specify only one system label.\n");
305    exit(EX_START);
306  }
307  if (argc == 1) dstsystem = *argv;
308
309  if (optc > 1) {
310    fprintf(stderr, "specify only one mode.\n");
311    exit(EX_START);
312  }
313}
314
315static void
316Greetings()
317{
318  printf("User Process PPP. Written by Toshiharu OHNO.\r\n");
319  fflush(stdout);
320}
321
322void
323main(argc, argv)
324int argc;
325char **argv;
326{
327  FILE *lockfile;
328  argc--; argv++;
329
330  mode = MODE_INTER;		/* default operation is interactive mode */
331  netfd = server = modem = tun_in = -1;
332  ProcessArgs(argc, argv);
333  Greetings();
334  GetUid();
335  IpcpDefAddress();
336
337  if (SelectSystem("default", CONFFILE) < 0) {
338    fprintf(stderr, "Warning: No default entry is given in config file.\n");
339  }
340
341  switch ( LocalAuthInit() ) {
342    case NOT_FOUND:
343    	fprintf(stderr,LAUTH_M1);
344    	fprintf(stderr,LAUTH_M2);
345	fflush (stderr);
346	/* Fall down */
347    case VALID:
348	VarLocalAuth = LOCAL_AUTH;
349	break;
350    default:
351	break;
352  }
353
354  if (OpenTunnel(&tunno) < 0) {
355    perror("open_tun");
356    exit(EX_START);
357  }
358
359  if (mode & (MODE_AUTO|MODE_DIRECT|MODE_DEDICATED))
360    mode &= ~MODE_INTER;
361  if (mode & MODE_INTER) {
362    printf("Interactive mode\n");
363    netfd = STDIN_FILENO;
364  } else if (mode & MODE_AUTO) {
365    printf("Automatic Dialer mode\n");
366    if (dstsystem == NULL) {
367      fprintf(stderr, "Destination system must be specified in"
368              " auto, background or ddial mode.\n");
369      exit(EX_START);
370    }
371  }
372
373  tcgetattr(0, &oldtio);		/* Save original tty mode */
374
375  pending_signal(SIGHUP, LogReOpen);
376  pending_signal(SIGTERM, CloseSession);
377  pending_signal(SIGINT, CloseSession);
378  pending_signal(SIGQUIT, CloseSession);
379#ifdef SIGSEGV
380  signal(SIGSEGV, Hangup);
381#endif
382#ifdef SIGPIPE
383  signal(SIGPIPE, SIG_IGN);
384#endif
385#ifdef SIGALRM
386  pending_signal(SIGALRM, SIG_IGN);
387#endif
388  if(mode & MODE_INTER)
389    {
390#ifdef SIGTSTP
391      pending_signal(SIGTSTP, TerminalStop);
392#endif
393#ifdef SIGTTIN
394      pending_signal(SIGTTIN, TerminalStop);
395#endif
396#ifdef SIGTTOU
397      pending_signal(SIGTTOU, SIG_IGN);
398#endif
399    }
400
401  if (dstsystem) {
402    if (SelectSystem(dstsystem, CONFFILE) < 0) {
403      fprintf(stderr, "Destination system not found in conf file.\n");
404      Cleanup(EX_START);
405    }
406    if ((mode & MODE_AUTO) && DefHisAddress.ipaddr.s_addr == INADDR_ANY) {
407      fprintf(stderr, "Must specify dstaddr with"
408              " auto, background or ddial mode.\n");
409      Cleanup(EX_START);
410    }
411  }
412  if (mode & MODE_DIRECT)
413    printf("Packet mode enabled.\n");
414
415  if (!(mode & MODE_INTER)) {
416    int port = SERVER_PORT + tunno;
417
418    if (mode & MODE_BACKGROUND) {
419      if (pipe (BGFiledes)) {
420	perror("pipe");
421	Cleanup(EX_SOCK);
422      }
423    }
424
425    /* Create server socket and listen at there. */
426    server = socket(PF_INET, SOCK_STREAM, 0);
427    if (server < 0) {
428      perror("socket");
429      Cleanup(EX_SOCK);
430    }
431    ifsin.sin_family = AF_INET;
432    ifsin.sin_addr.s_addr = INADDR_ANY;
433    ifsin.sin_port = htons(port);
434    setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &server, sizeof server);
435    if (bind(server, (struct sockaddr *) &ifsin, sizeof(ifsin)) < 0) {
436      perror("bind");
437      if (errno == EADDRINUSE)
438        fprintf(stderr, "Wait for a while, then try again.\n");
439      Cleanup(EX_SOCK);
440    }
441    if (listen(server, 5) != 0) {
442      fprintf(stderr, "Unable to listen to socket - OS overload?\n");
443    }
444
445    DupLog();
446    if (!(mode & MODE_DIRECT)) {
447      pid_t bgpid;
448
449      bgpid = fork ();
450      if (bgpid == -1) {
451	perror ("fork");
452	Cleanup (EX_SOCK);
453      }
454      if (bgpid) {
455	char c = EX_NORMAL;
456
457	if (mode & MODE_BACKGROUND) {
458	  /* Wait for our child to close its pipe before we exit. */
459	  BGPid = bgpid;
460          close (BGFiledes[1]);
461	  if (read(BGFiledes[0], &c, 1) != 1) {
462	    printf("Child exit, no status.\n");
463	    LogPrintf (LOG_PHASE_BIT, "Parent: Child exit, no status.\n");
464	  } else if (c == EX_NORMAL) {
465	    printf("PPP enabled.\n");
466	    LogPrintf (LOG_PHASE_BIT, "Parent: PPP enabled.\n");
467	  } else {
468	    printf("Child failed (%s).\n",ex_desc((int)c));
469	    LogPrintf(LOG_PHASE_BIT, "Parent: Child failed (%s).\n",
470                      ex_desc((int)c));
471          }
472          close (BGFiledes[0]);
473	}
474        exit(c);
475      } else if (mode & MODE_BACKGROUND)
476          close(BGFiledes[0]);
477    }
478
479    snprintf(pid_filename, sizeof (pid_filename), "%stun%d.pid",
480             _PATH_VARRUN, tunno);
481    (void)unlink(pid_filename);
482
483    if ((lockfile = fopen(pid_filename, "w")) != NULL) {
484      fprintf(lockfile, "%d\n", (int)getpid());
485      fclose(lockfile);
486    } else
487      logprintf("Warning: Can't create %s: %s\n", pid_filename, strerror(errno));
488
489    snprintf(if_filename, sizeof if_filename, "%s%s.if",
490             _PATH_VARRUN, VarBaseDevice);
491    (void)unlink(if_filename);
492
493    if ((lockfile = fopen(if_filename, "w")) != NULL) {
494      fprintf(lockfile, "tun%d\n", tunno);
495      fclose(lockfile);
496    } else
497      logprintf("Warning: Can't create %s: %s\n", if_filename, strerror(errno));
498
499    if (server >= 0)
500	LogPrintf(LOG_PHASE_BIT, "Listening at %d.\n", port);
501#ifdef DOTTYINIT
502    if (mode & (MODE_DIRECT|MODE_DEDICATED)) { /* } */
503#else
504    if (mode & MODE_DIRECT) {
505#endif
506      TtyInit();
507    } else {
508      int fd;
509
510      setsid();			/* detach control tty */
511      if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
512	(void)dup2(fd, STDIN_FILENO);
513	(void)dup2(fd, STDOUT_FILENO);
514	(void)dup2(fd, STDERR_FILENO);
515	if (fd > 2)
516		(void)close (fd);
517      }
518    }
519  } else {
520    TtyInit();
521    TtyCommandMode(1);
522  }
523  LogPrintf(LOG_PHASE_BIT, "PPP Started.\n");
524
525
526  do
527   DoLoop();
528  while (mode & MODE_DEDICATED);
529
530  Cleanup(EX_DONE);
531}
532
533/*
534 *  Turn into packet mode, where we speak PPP.
535 */
536void
537PacketMode()
538{
539  if (RawModem(modem) < 0) {
540    fprintf(stderr, "Not connected.\r\n");
541    return;
542  }
543
544  AsyncInit();
545  VjInit();
546  LcpInit();
547  IpcpInit();
548  CcpInit();
549  LcpUp();
550
551  LcpOpen(VarOpenMode);
552  if ((mode & (MODE_INTER|MODE_AUTO)) == MODE_INTER) {
553    TtyCommandMode(1);
554    fprintf(stderr, "Packet mode.\r\n");
555    aft_cmd = 1;
556  }
557}
558
559static void
560ShowHelp()
561{
562  fprintf(stderr, "The following commands are available:\r\n");
563  fprintf(stderr, " ~p\tEnter to Packet mode\r\n");
564  fprintf(stderr, " ~-\tDecrease log level\r\n");
565  fprintf(stderr, " ~+\tIncrease log level\r\n");
566  fprintf(stderr, " ~.\tTerminate program\r\n");
567  fprintf(stderr, " ~?\tThis help\r\n");
568}
569
570static void
571ReadTty()
572{
573  int n;
574  char ch;
575  static int ttystate;
576#define MAXLINESIZE 200
577  char linebuff[MAXLINESIZE];
578
579#ifdef DEBUG
580  logprintf("termode = %d, netfd = %d, mode = %d\n", TermMode, netfd, mode);
581#endif
582  if (!TermMode) {
583    n = read(netfd, linebuff, sizeof(linebuff)-1);
584    aft_cmd = 1;
585    if (n > 0) {
586      DecodeCommand(linebuff, n, 1);
587    } else {
588      LogPrintf(LOG_PHASE_BIT, "client connection closed.\n");
589      VarLocalAuth = LOCAL_NO_AUTH;
590      close(netfd);
591      close(1);
592      dup2(2, 1);     /* Have to have something here or the modem will be 1 */
593      netfd = -1;
594      mode &= ~MODE_INTER;
595    }
596    return;
597  }
598
599  /*
600   *  We are in terminal mode, decode special sequences
601   */
602  n = read(0, &ch, 1);
603#ifdef DEBUG
604  logprintf("got %d bytes\n", n);
605#endif
606
607  if (n > 0) {
608    switch (ttystate) {
609    case 0:
610      if (ch == '~')
611	ttystate++;
612      else
613	write(modem, &ch, n);
614      break;
615    case 1:
616      switch (ch) {
617      case '?':
618	ShowHelp();
619	break;
620      case '-':
621	if (loglevel > 0) {
622	  loglevel--;
623	  fprintf(stderr, "New loglevel is %d\r\n", loglevel);
624	}
625	break;
626      case '+':
627	loglevel++;
628	fprintf(stderr, "New loglevel is %d\r\n", loglevel);
629	break;
630#ifdef DEBUG
631      case 'm':
632	ShowMemMap();
633	break;
634#endif
635      case 'p':
636	/*
637	 * XXX: Should check carrier.
638	 */
639	if (LcpFsm.state <= ST_CLOSED) {
640	  VarOpenMode = OPEN_ACTIVE;
641	  PacketMode();
642	}
643	break;
644#ifdef DEBUG
645      case 't':
646	ShowTimers();
647	break;
648#endif
649      case '.':
650	TermMode = 1;
651	TtyCommandMode(1);
652	break;
653      default:
654	if (write(modem, &ch, n) < 0)
655	  fprintf(stderr, "err in write.\r\n");
656	break;
657      }
658      ttystate = 0;
659      break;
660    }
661  }
662}
663
664
665/*
666 *  Here, we'll try to detect HDLC frame
667 */
668
669static char *FrameHeaders[] = {
670  "\176\377\003\300\041",
671  "\176\377\175\043\300\041",
672  "\176\177\175\043\100\041",
673  "\176\175\337\175\043\300\041",
674  "\176\175\137\175\043\100\041",
675  NULL,
676};
677
678u_char *
679HdlcDetect(cp, n)
680u_char *cp;
681int n;
682{
683  char *ptr, *fp, **hp;
684
685  cp[n] = '\0';	/* be sure to null terminated */
686  ptr = NULL;
687  for (hp = FrameHeaders; *hp; hp++) {
688    fp = *hp;
689    if (DEV_IS_SYNC)
690      fp++;
691    ptr = strstr((char *)cp, fp);
692    if (ptr)
693      break;
694  }
695  return((u_char *)ptr);
696}
697
698static struct pppTimer RedialTimer;
699
700static void
701RedialTimeout()
702{
703  StopTimer(&RedialTimer);
704  LogPrintf(LOG_PHASE_BIT, "Redialing timer expired.\n");
705}
706
707static void
708StartRedialTimer(Timeout)
709	int Timeout;
710{
711  StopTimer(&RedialTimer);
712
713  if (Timeout) {
714    RedialTimer.state = TIMER_STOPPED;
715
716    if (Timeout > 0)
717	RedialTimer.load = Timeout * SECTICKS;
718    else
719	RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS;
720
721    LogPrintf(LOG_PHASE_BIT, "Enter pause (%d) for redialing.\n",
722	      RedialTimer.load / SECTICKS);
723
724    RedialTimer.func = RedialTimeout;
725    StartTimer(&RedialTimer);
726  }
727}
728
729
730static void
731DoLoop()
732{
733  fd_set rfds, wfds, efds;
734  int pri, i, n, wfd, nfds;
735  struct sockaddr_in hisaddr;
736  struct timeval timeout, *tp;
737  int ssize = sizeof(hisaddr);
738  u_char *cp;
739  u_char rbuff[MAX_MRU];
740  int dial_up;
741  int tries;
742  int qlen;
743  pid_t pgroup;
744
745  pgroup = getpgrp();
746
747  if (mode & MODE_DIRECT) {
748    modem = OpenModem(mode);
749    LogPrintf(LOG_PHASE_BIT, "Packet mode enabled\n");
750    fflush(stderr);
751    PacketMode();
752  } else if (mode & MODE_DEDICATED) {
753    if (modem < 0)
754      modem = OpenModem(mode);
755  }
756
757  fflush(stdout);
758
759  timeout.tv_sec = 0;
760  timeout.tv_usec = 0;
761  reconnectState = RECON_UNKNOWN;
762
763  if (mode & MODE_BACKGROUND)
764    dial_up = TRUE;			/* Bring the line up */
765  else
766    dial_up = FALSE;			/* XXXX */
767  tries = 0;
768  for (;;) {
769    nfds = 0;
770    FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds);
771
772    /*
773     * If the link is down and we're in DDIAL mode, bring it back
774     * up.
775     */
776    if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED)
777        dial_up = TRUE;
778
779    /*
780     * If we lost carrier and want to re-establish the connection
781     * due to the "set reconnect" value, we'd better bring the line
782     * back up.
783     */
784    if (LcpFsm.state <= ST_CLOSED) {
785      if (dial_up != TRUE && reconnectState == RECON_TRUE) {
786        if (++reconnectCount <= VarReconnectTries) {
787          LogPrintf(LOG_PHASE_BIT, "Connection lost, re-establish (%d/%d)\n",
788                    reconnectCount, VarReconnectTries);
789	  StartRedialTimer(VarReconnectTimer);
790          dial_up = TRUE;
791        } else {
792          if (VarReconnectTries)
793            LogPrintf(LOG_PHASE_BIT, "Connection lost, maximum (%d) times\n",
794                      VarReconnectTries);
795          reconnectCount = 0;
796          if (mode & MODE_BACKGROUND)
797            Cleanup(EX_DEAD);
798        }
799        reconnectState = RECON_ENVOKED;
800      }
801    }
802
803   /*
804    * If Ip packet for output is enqueued and require dial up,
805    * Just do it!
806    */
807    if ( dial_up && RedialTimer.state != TIMER_RUNNING ) {
808#ifdef DEBUG
809      logprintf("going to dial: modem = %d\n", modem);
810#endif
811      modem = OpenModem(mode);
812      if (modem < 0) {
813	StartRedialTimer(VarRedialTimeout);
814      } else {
815	tries++;    /* Tries are per number, not per list of numbers. */
816        if (VarDialTries)
817	  LogPrintf(LOG_CHAT_BIT, "Dial attempt %u of %d\n", tries,
818		    VarDialTries);
819        else
820	  LogPrintf(LOG_CHAT_BIT, "Dial attempt %u\n", tries);
821	if (DialModem()) {
822	  sleep(1);	       /* little pause to allow peer starts */
823	  ModemTimeout();
824	  PacketMode();
825	  dial_up = FALSE;
826          reconnectState = RECON_UNKNOWN;
827	  tries = 0;
828	} else {
829	  CloseModem();
830	  if (mode & MODE_BACKGROUND) {
831	    if (VarNextPhone == NULL)
832	      Cleanup(EX_DIAL);  /* Tried all numbers - no luck */
833	    else
834	      /* Try all numbers in background mode */
835	      StartRedialTimer(VarRedialNextTimeout);
836	  } else if (VarDialTries && tries >= VarDialTries) {
837	    /* I give up !  Can't get through :( */
838	    StartRedialTimer(VarRedialTimeout);
839	    dial_up = FALSE;
840            reconnectState = RECON_UNKNOWN;
841            reconnectCount = 0;
842	    tries = 0;
843	  } else if (VarNextPhone == NULL)
844	    /* Dial failed. Keep quite during redial wait period. */
845	    StartRedialTimer(VarRedialTimeout);
846	  else
847	    StartRedialTimer(VarRedialNextTimeout);
848	}
849      }
850    }
851    qlen = ModemQlen();
852
853    if (qlen == 0) {
854      IpStartOutput();
855      qlen = ModemQlen();
856    }
857
858    if (modem >= 0) {
859      if (modem + 1 > nfds)
860	nfds = modem + 1;
861      FD_SET(modem, &rfds);
862      FD_SET(modem, &efds);
863      if (qlen > 0) {
864	FD_SET(modem, &wfds);
865      }
866    }
867    if (server >= 0) {
868      if (server + 1 > nfds)
869	nfds = server + 1;
870      FD_SET(server, &rfds);
871    }
872
873    /*  *** IMPORTANT ***
874     *
875     *  CPU is serviced every TICKUNIT micro seconds.
876     *	This value must be chosen with great care. If this values is
877     *  too big, it results loss of characters from modem and poor responce.
878     *  If this values is too small, ppp process eats many CPU time.
879     */
880#ifndef SIGALRM
881    usleep(TICKUNIT);
882    TimerService();
883#else
884    handle_signals();
885#endif
886
887    /* If there are aren't many packets queued, look for some more. */
888    if (qlen < 20 && tun_in >= 0) {
889      if (tun_in + 1 > nfds)
890	nfds = tun_in + 1;
891      FD_SET(tun_in, &rfds);
892    }
893
894    if (netfd >= 0) {
895      if (netfd + 1 > nfds)
896	nfds = netfd + 1;
897      FD_SET(netfd, &rfds);
898      FD_SET(netfd, &efds);
899    }
900
901#ifndef SIGALRM
902    /*
903     *  Normally, select() will not block because modem is writable.
904     *  In AUTO mode, select will block until we find packet from tun
905     */
906    tp = (RedialTimer.state == TIMER_RUNNING)? &timeout : NULL;
907    i = select(nfds, &rfds, &wfds, &efds, tp);
908#else
909    /*
910     * When SIGALRM timer is running, a select function will be
911     * return -1 and EINTR after a Time Service signal hundler
912     * is done.  If the redial timer is not running and we are
913     * trying to dial, poll with a 0 value timer.
914     */
915    tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL;
916    i = select(nfds, &rfds, &wfds, &efds, tp);
917#endif
918
919    if ( i == 0 ) {
920        continue;
921    }
922
923    if ( i < 0 ) {
924       if ( errno == EINTR ) {
925          handle_signals();
926          continue;
927       }
928       perror("select");
929       break;
930    }
931
932    if ((netfd >= 0 && FD_ISSET(netfd, &efds)) || (modem >= 0 && FD_ISSET(modem, &efds))) {
933      logprintf("Exception detected.\n");
934      break;
935    }
936
937    if (server >= 0 && FD_ISSET(server, &rfds)) {
938      LogPrintf(LOG_PHASE_BIT, "connected to client.\n");
939      wfd = accept(server, (struct sockaddr *)&hisaddr, &ssize);
940      if (wfd < 0) {
941	perror("accept");
942	continue;
943      }
944      if (netfd >= 0) {
945	write(wfd, "already in use.\n", 16);
946	close(wfd);
947	continue;
948      } else
949	netfd = wfd;
950      if (dup2(netfd, 1) < 0) {
951	perror("dup2");
952	close(netfd);
953	netfd = -1;
954	continue;
955      }
956      mode |= MODE_INTER;
957      Greetings();
958      switch ( LocalAuthInit() ) {
959         case NOT_FOUND:
960    	    fprintf(stdout,LAUTH_M1);
961    	    fprintf(stdout,LAUTH_M2);
962            fflush(stdout);
963	    /* Fall down */
964         case VALID:
965	    VarLocalAuth = LOCAL_AUTH;
966	    break;
967         default:
968	    break;
969      }
970      (void) IsInteractive();
971      Prompt();
972    }
973
974    if ((mode & MODE_INTER) && (netfd >= 0 && FD_ISSET(netfd, &rfds)) &&
975	((mode & MODE_AUTO) || pgroup == tcgetpgrp(0))) {
976      /* something to read from tty */
977      ReadTty();
978    }
979    if (modem >= 0) {
980      if (FD_ISSET(modem, &wfds)) {	/* ready to write into modem */
981	 ModemStartOutput(modem);
982      }
983      if (FD_ISSET(modem, &rfds)) {	/* something to read from modem */
984	if (LcpFsm.state <= ST_CLOSED)
985	  usleep(10000);
986	n = read(modem, rbuff, sizeof(rbuff));
987	if ((mode & MODE_DIRECT) && n <= 0) {
988	  DownConnection();
989	} else
990          LogDumpBuff(LOG_ASYNC, "ReadFromModem", rbuff, n);
991
992	if (LcpFsm.state <= ST_CLOSED) {
993	  /*
994	   *  In dedicated mode, we just discard input until LCP is started.
995	   */
996	  if (!(mode & MODE_DEDICATED)) {
997	    cp = HdlcDetect(rbuff, n);
998	    if (cp) {
999	      /*
1000	       * LCP packet is detected. Turn ourselves into packet mode.
1001	       */
1002	      if (cp != rbuff) {
1003	        write(1, rbuff, cp - rbuff);
1004	        write(1, "\r\n", 2);
1005	      }
1006	      PacketMode();
1007	    } else
1008	      write(1, rbuff, n);
1009	  }
1010	} else {
1011	  if (n > 0)
1012	    AsyncInput(rbuff, n);
1013	}
1014      }
1015    }
1016
1017    if (tun_in >= 0 && FD_ISSET(tun_in, &rfds)) {       /* something to read from tun */
1018      n = read(tun_in, rbuff, sizeof(rbuff));
1019      if (n < 0) {
1020	perror("read from tun");
1021	continue;
1022      }
1023      /*
1024       *  Process on-demand dialup. Output packets are queued within tunnel
1025       *  device until IPCP is opened.
1026       */
1027      if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) {
1028	pri = PacketCheck(rbuff, n, FL_DIAL);
1029	if (pri >= 0) {
1030	  if (mode & MODE_ALIAS) {
1031	    VarPacketAliasOut(rbuff, sizeof rbuff);
1032	    n = ntohs(((struct ip *)rbuff)->ip_len);
1033	  }
1034	  IpEnqueue(pri, rbuff, n);
1035	  dial_up = TRUE;		/* XXX */
1036	}
1037	continue;
1038      }
1039      pri = PacketCheck(rbuff, n, FL_OUT);
1040      if (pri >= 0) {
1041        if (mode & MODE_ALIAS) {
1042          VarPacketAliasOut(rbuff, sizeof rbuff);
1043          n = ntohs(((struct ip *)rbuff)->ip_len);
1044        }
1045	IpEnqueue(pri, rbuff, n);
1046      }
1047    }
1048  }
1049  logprintf("job done.\n");
1050}
1051