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