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