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