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