xref: /freebsd/usr.sbin/ppp/main.c (revision 0de89efe5c443f213c7ea28773ef2dc6cf3af2ed)
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.80 1997/09/21 20:26:46 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(), 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();
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       DecodeCommand(linebuff, n, 1);
551     } else {
552       LogPrintf(LogPHASE, "client connection closed.\n");
553       VarLocalAuth = LOCAL_NO_AUTH;
554       mode &= ~MODE_INTER;
555       oVarTerm = VarTerm;
556       VarTerm = 0;
557       if (oVarTerm && oVarTerm != stdout)
558 	fclose(oVarTerm);
559       close(netfd);
560       netfd = -1;
561     }
562     return;
563   }
564 
565   /*
566    * We are in terminal mode, decode special sequences
567    */
568   n = read(fileno(VarTerm), &ch, 1);
569   LogPrintf(LogDEBUG, "Got %d bytes (reading from the terminal)\n", n);
570 
571   if (n > 0) {
572     switch (ttystate) {
573     case 0:
574       if (ch == '~')
575 	ttystate++;
576       else
577 	write(modem, &ch, n);
578       break;
579     case 1:
580       switch (ch) {
581       case '?':
582 	ShowHelp();
583 	break;
584       case 'p':
585 
586 	/*
587 	 * XXX: Should check carrier.
588 	 */
589 	if (LcpFsm.state <= ST_CLOSED) {
590 	  VarOpenMode = OPEN_ACTIVE;
591 	  PacketMode();
592 	}
593 	break;
594       case '.':
595 	TermMode = 1;
596 	aft_cmd = 1;
597 	TtyCommandMode(1);
598 	break;
599       case 't':
600 	if (LogIsKept(LogDEBUG)) {
601 	  ShowTimers();
602 	  break;
603 	}
604       case 'm':
605 	if (LogIsKept(LogDEBUG)) {
606 	  ShowMemMap();
607 	  break;
608 	}
609       default:
610 	if (write(modem, &ch, n) < 0)
611 	  LogPrintf(LogERROR, "error writing to modem.\n");
612 	break;
613       }
614       ttystate = 0;
615       break;
616     }
617   }
618 }
619 
620 
621 /*
622  *  Here, we'll try to detect HDLC frame
623  */
624 
625 static char *FrameHeaders[] = {
626   "\176\377\003\300\041",
627   "\176\377\175\043\300\041",
628   "\176\177\175\043\100\041",
629   "\176\175\337\175\043\300\041",
630   "\176\175\137\175\043\100\041",
631   NULL,
632 };
633 
634 u_char *
635 HdlcDetect(u_char * cp, int n)
636 {
637   char *ptr, *fp, **hp;
638 
639   cp[n] = '\0';			/* be sure to null terminated */
640   ptr = NULL;
641   for (hp = FrameHeaders; *hp; hp++) {
642     fp = *hp;
643     if (DEV_IS_SYNC)
644       fp++;
645     ptr = strstr((char *) cp, fp);
646     if (ptr)
647       break;
648   }
649   return ((u_char *) ptr);
650 }
651 
652 static struct pppTimer RedialTimer;
653 
654 static void
655 RedialTimeout()
656 {
657   StopTimer(&RedialTimer);
658   LogPrintf(LogPHASE, "Redialing timer expired.\n");
659 }
660 
661 static void
662 StartRedialTimer(int Timeout)
663 {
664   StopTimer(&RedialTimer);
665 
666   if (Timeout) {
667     RedialTimer.state = TIMER_STOPPED;
668 
669     if (Timeout > 0)
670       RedialTimer.load = Timeout * SECTICKS;
671     else
672       RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS;
673 
674     LogPrintf(LogPHASE, "Enter pause (%d) for redialing.\n",
675 	      RedialTimer.load / SECTICKS);
676 
677     RedialTimer.func = RedialTimeout;
678     StartTimer(&RedialTimer);
679   }
680 }
681 
682 
683 static void
684 DoLoop()
685 {
686   fd_set rfds, wfds, efds;
687   int pri, i, n, wfd, nfds;
688   struct sockaddr_in hisaddr;
689   struct timeval timeout, *tp;
690   int ssize = sizeof(hisaddr);
691   u_char *cp;
692   u_char rbuff[MAX_MRU];
693   int tries;
694   int qlen;
695   int res;
696   pid_t pgroup;
697 
698   pgroup = getpgrp();
699 
700   if (mode & MODE_DIRECT) {
701     LogPrintf(LogDEBUG, "Opening modem\n");
702     if (OpenModem(mode) < 0)
703       return;
704     LogPrintf(LogPHASE, "Packet mode enabled\n");
705     PacketMode();
706   } else if (mode & MODE_DEDICATED) {
707     if (modem < 0)
708       while (OpenModem(mode) < 0)
709 	sleep(VarReconnectTimer);
710   }
711   fflush(VarTerm);
712 
713   timeout.tv_sec = 0;
714   timeout.tv_usec = 0;
715   reconnectState = RECON_UNKNOWN;
716 
717   if (mode & MODE_BACKGROUND)
718     dial_up = TRUE;		/* Bring the line up */
719   else
720     dial_up = FALSE;		/* XXXX */
721   tries = 0;
722   for (;;) {
723     nfds = 0;
724     FD_ZERO(&rfds);
725     FD_ZERO(&wfds);
726     FD_ZERO(&efds);
727 
728     /*
729      * If the link is down and we're in DDIAL mode, bring it back up.
730      */
731     if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED)
732       dial_up = TRUE;
733 
734     /*
735      * If we lost carrier and want to re-establish the connection due to the
736      * "set reconnect" value, we'd better bring the line back up.
737      */
738     if (LcpFsm.state <= ST_CLOSED) {
739       if (dial_up != TRUE && reconnectState == RECON_TRUE) {
740 	if (++reconnectCount <= VarReconnectTries) {
741 	  LogPrintf(LogPHASE, "Connection lost, re-establish (%d/%d)\n",
742 		    reconnectCount, VarReconnectTries);
743 	  StartRedialTimer(VarReconnectTimer);
744 	  dial_up = TRUE;
745 	} else {
746 	  if (VarReconnectTries)
747 	    LogPrintf(LogPHASE, "Connection lost, maximum (%d) times\n",
748 		      VarReconnectTries);
749 	  reconnectCount = 0;
750 	  if (mode & MODE_BACKGROUND)
751 	    Cleanup(EX_DEAD);
752 	}
753 	reconnectState = RECON_ENVOKED;
754       }
755     }
756 
757     /*
758      * If Ip packet for output is enqueued and require dial up, Just do it!
759      */
760     if (dial_up && RedialTimer.state != TIMER_RUNNING) {
761       LogPrintf(LogDEBUG, "going to dial: modem = %d\n", modem);
762       if (OpenModem(mode) < 0) {
763 	tries++;
764 	if (!(mode & MODE_DDIAL) && VarDialTries)
765 	  LogPrintf(LogCHAT, "Failed to open modem (attempt %u of %d)\n",
766 		    tries, VarDialTries);
767 	else
768 	  LogPrintf(LogCHAT, "Failed to open modem (attempt %u)\n", tries);
769 
770 	if (!(mode & MODE_DDIAL) && VarDialTries && tries >= VarDialTries) {
771 	  if (mode & MODE_BACKGROUND)
772 	    Cleanup(EX_DIAL);	/* Can't get the modem */
773 	  dial_up = FALSE;
774 	  reconnectState = RECON_UNKNOWN;
775 	  reconnectCount = 0;
776 	  tries = 0;
777 	} else
778 	  StartRedialTimer(VarRedialTimeout);
779       } else {
780 	tries++;		/* Tries are per number, not per list of
781 				 * numbers. */
782 	if (!(mode & MODE_DDIAL) && VarDialTries)
783 	  LogPrintf(LogCHAT, "Dial attempt %u of %d\n", tries, VarDialTries);
784 	else
785 	  LogPrintf(LogCHAT, "Dial attempt %u\n", tries);
786 
787 	if ((res = DialModem()) == EX_DONE) {
788 	  sleep(1);		/* little pause to allow peer starts */
789 	  ModemTimeout();
790 	  PacketMode();
791 	  dial_up = FALSE;
792 	  reconnectState = RECON_UNKNOWN;
793 	  tries = 0;
794 	} else {
795 	  CloseModem();
796 	  if (mode & MODE_BACKGROUND) {
797 	    if (VarNextPhone == NULL || res == EX_SIG)
798 	      Cleanup(EX_DIAL);	/* Tried all numbers - no luck */
799 	    else
800 	      /* Try all numbers in background mode */
801 	      StartRedialTimer(VarRedialNextTimeout);
802 	  } else if (!(mode & MODE_DDIAL) &&
803 		     ((VarDialTries && tries >= VarDialTries) ||
804 		      res == EX_SIG)) {
805 	    /* I give up !  Can't get through :( */
806 	    StartRedialTimer(VarRedialTimeout);
807 	    dial_up = FALSE;
808 	    reconnectState = RECON_UNKNOWN;
809 	    reconnectCount = 0;
810 	    tries = 0;
811 	  } else if (VarNextPhone == NULL)
812 	    /* Dial failed. Keep quite during redial wait period. */
813 	    StartRedialTimer(VarRedialTimeout);
814 	  else
815 	    StartRedialTimer(VarRedialNextTimeout);
816 	}
817       }
818     }
819     qlen = ModemQlen();
820 
821     if (qlen == 0) {
822       IpStartOutput();
823       qlen = ModemQlen();
824     }
825     if (modem >= 0) {
826       if (modem + 1 > nfds)
827 	nfds = modem + 1;
828       FD_SET(modem, &rfds);
829       FD_SET(modem, &efds);
830       if (qlen > 0) {
831 	FD_SET(modem, &wfds);
832       }
833     }
834     if (server >= 0) {
835       if (server + 1 > nfds)
836 	nfds = server + 1;
837       FD_SET(server, &rfds);
838     }
839 
840     /*
841      * *** IMPORTANT ***
842      *
843      * CPU is serviced every TICKUNIT micro seconds. This value must be chosen
844      * with great care. If this values is too big, it results loss of
845      * characters from modem and poor responce. If this values is too small,
846      * ppp process eats many CPU time.
847      */
848 #ifndef SIGALRM
849     usleep(TICKUNIT);
850     TimerService();
851 #else
852     handle_signals();
853 #endif
854 
855     /* If there are aren't many packets queued, look for some more. */
856     if (qlen < 20 && tun_in >= 0) {
857       if (tun_in + 1 > nfds)
858 	nfds = tun_in + 1;
859       FD_SET(tun_in, &rfds);
860     }
861     if (netfd >= 0) {
862       if (netfd + 1 > nfds)
863 	nfds = netfd + 1;
864       FD_SET(netfd, &rfds);
865       FD_SET(netfd, &efds);
866     }
867 #ifndef SIGALRM
868 
869     /*
870      * Normally, select() will not block because modem is writable. In AUTO
871      * mode, select will block until we find packet from tun
872      */
873     tp = (RedialTimer.state == TIMER_RUNNING) ? &timeout : NULL;
874     i = select(nfds, &rfds, &wfds, &efds, tp);
875 #else
876 
877     /*
878      * When SIGALRM timer is running, a select function will be return -1 and
879      * EINTR after a Time Service signal hundler is done.  If the redial
880      * timer is not running and we are trying to dial, poll with a 0 value
881      * timer.
882      */
883     tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL;
884     i = select(nfds, &rfds, &wfds, &efds, tp);
885 #endif
886 
887     if (i == 0) {
888       continue;
889     }
890     if (i < 0) {
891       if (errno == EINTR) {
892 	handle_signals();
893 	continue;
894       }
895       LogPrintf(LogERROR, "DoLoop: select(): %s\n", strerror(errno));
896       break;
897     }
898     if ((netfd >= 0 && FD_ISSET(netfd, &efds)) || (modem >= 0 && FD_ISSET(modem, &efds))) {
899       LogPrintf(LogALERT, "Exception detected.\n");
900       break;
901     }
902     if (server >= 0 && FD_ISSET(server, &rfds)) {
903       LogPrintf(LogPHASE, "connected to client.\n");
904       wfd = accept(server, (struct sockaddr *) & hisaddr, &ssize);
905       if (wfd < 0) {
906 	LogPrintf(LogERROR, "DoLoop: accept(): %s\n", strerror(errno));
907 	continue;
908       }
909       if (netfd >= 0) {
910 	write(wfd, "already in use.\n", 16);
911 	close(wfd);
912 	continue;
913       } else
914 	netfd = wfd;
915       VarTerm = fdopen(netfd, "a+");
916       mode |= MODE_INTER;
917       Greetings();
918       (void) IsInteractive();
919       Prompt();
920     }
921     if ((mode & MODE_INTER) && (netfd >= 0 && FD_ISSET(netfd, &rfds)) &&
922 	((mode & MODE_AUTO) || pgroup == tcgetpgrp(0))) {
923       /* something to read from tty */
924       ReadTty();
925     }
926     if (modem >= 0) {
927       if (FD_ISSET(modem, &wfds)) {	/* ready to write into modem */
928 	ModemStartOutput(modem);
929       }
930       if (FD_ISSET(modem, &rfds)) {	/* something to read from modem */
931 	if (LcpFsm.state <= ST_CLOSED)
932 	  usleep(10000);
933 	n = read(modem, rbuff, sizeof(rbuff));
934 	if ((mode & MODE_DIRECT) && n <= 0) {
935 	  DownConnection();
936 	} else
937 	  LogDumpBuff(LogASYNC, "ReadFromModem", rbuff, n);
938 
939 	if (LcpFsm.state <= ST_CLOSED) {
940 
941 	  /*
942 	   * In dedicated mode, we just discard input until LCP is started.
943 	   */
944 	  if (!(mode & MODE_DEDICATED)) {
945 	    cp = HdlcDetect(rbuff, n);
946 	    if (cp) {
947 
948 	      /*
949 	       * LCP packet is detected. Turn ourselves into packet mode.
950 	       */
951 	      if (cp != rbuff) {
952 		write(modem, rbuff, cp - rbuff);
953 		write(modem, "\r\n", 2);
954 	      }
955 	      PacketMode();
956 	    } else
957 	      write(fileno(VarTerm), rbuff, n);
958 	  }
959 	} else {
960 	  if (n > 0)
961 	    AsyncInput(rbuff, n);
962 	}
963       }
964     }
965     if (tun_in >= 0 && FD_ISSET(tun_in, &rfds)) {	/* something to read
966 							 * from tun */
967       n = read(tun_in, rbuff, sizeof(rbuff));
968       if (n < 0) {
969 	LogPrintf(LogERROR, "read from tun: %s\n", strerror(errno));
970 	continue;
971       }
972       if (((struct ip *) rbuff)->ip_dst.s_addr == IpcpInfo.want_ipaddr.s_addr) {
973 	/* we've been asked to send something addressed *to* us :( */
974 	if (VarLoopback) {
975 	  pri = PacketCheck(rbuff, n, FL_IN);
976 	  if (pri >= 0) {
977 	    struct mbuf *bp;
978 
979 	    if (mode & MODE_ALIAS) {
980 	      VarPacketAliasIn(rbuff, sizeof rbuff);
981 	      n = ntohs(((struct ip *) rbuff)->ip_len);
982 	    }
983 	    bp = mballoc(n, MB_IPIN);
984 	    bcopy(rbuff, MBUF_CTOP(bp), n);
985 	    IpInput(bp);
986 	    LogPrintf(LogDEBUG, "Looped back packet addressed to myself\n");
987 	  }
988 	  continue;
989 	} else
990 	  LogPrintf(LogDEBUG, "Oops - forwarding packet addressed to myself\n");
991       }
992 
993       /*
994        * Process on-demand dialup. Output packets are queued within tunnel
995        * device until IPCP is opened.
996        */
997       if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) {
998 	pri = PacketCheck(rbuff, n, FL_DIAL);
999 	if (pri >= 0) {
1000 	  if (mode & MODE_ALIAS) {
1001 	    VarPacketAliasOut(rbuff, sizeof rbuff);
1002 	    n = ntohs(((struct ip *) rbuff)->ip_len);
1003 	  }
1004 	  IpEnqueue(pri, rbuff, n);
1005 	  dial_up = TRUE;	/* XXX */
1006 	}
1007 	continue;
1008       }
1009       pri = PacketCheck(rbuff, n, FL_OUT);
1010       if (pri >= 0) {
1011 	if (mode & MODE_ALIAS) {
1012 	  VarPacketAliasOut(rbuff, sizeof rbuff);
1013 	  n = ntohs(((struct ip *) rbuff)->ip_len);
1014 	}
1015 	IpEnqueue(pri, rbuff, n);
1016       }
1017     }
1018   }
1019   LogPrintf(LogDEBUG, "Job (DoLoop) done.\n");
1020 }
1021