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