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