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