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