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