main.c revision 24843
1129198Scognet/*
2129198Scognet *			User Process PPP
3139735Simp *
4129198Scognet *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5129198Scognet *
6129198Scognet *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
7129198Scognet *
8129198Scognet * Redistribution and use in source and binary forms are permitted
9129198Scognet * provided that the above copyright notice and this paragraph are
10129198Scognet * duplicated in all such forms and that any documentation,
11129198Scognet * advertising materials, and other materials related to such
12129198Scognet * distribution and use acknowledge that the software was developed
13129198Scognet * by the Internet Initiative Japan, Inc.  The name of the
14129198Scognet * IIJ may not be used to endorse or promote products derived
15129198Scognet * from this software without specific prior written permission.
16129198Scognet * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17129198Scognet * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18129198Scognet * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19129198Scognet *
20129198Scognet * $Id: main.c,v 1.41 1997/04/09 17:35:54 ache Exp $
21129198Scognet *
22129198Scognet *	TODO:
23129198Scognet *		o Add commands for traffic summary, version display, etc.
24129198Scognet *		o Add signal handler for misc controls.
25129198Scognet */
26129198Scognet#include "fsm.h"
27129198Scognet#include <fcntl.h>
28129198Scognet#include <paths.h>
29129198Scognet#include <sys/time.h>
30129198Scognet#include <termios.h>
31129198Scognet#include <signal.h>
32129198Scognet#include <sys/wait.h>
33129198Scognet#include <errno.h>
34129198Scognet#include <netdb.h>
35129198Scognet#include <unistd.h>
36129198Scognet#include <sys/socket.h>
37129198Scognet#include <arpa/inet.h>
38129198Scognet#include <netinet/in_systm.h>
39129198Scognet#include <netinet/ip.h>
40129198Scognet#include "modem.h"
41129198Scognet#include "os.h"
42129198Scognet#include "hdlc.h"
43129198Scognet#include "ccp.h"
44129198Scognet#include "lcp.h"
45129198Scognet#include "ipcp.h"
46129198Scognet#include "vars.h"
47129198Scognet#include "auth.h"
48129198Scognet#include "filter.h"
49129198Scognet#include "systems.h"
50129198Scognet#include "ip.h"
51129198Scognet#include "alias.h"
52129198Scognet#include "sig.h"
53129198Scognet
54129198Scognet#define LAUTH_M1 "Warning: No password entry for this host in ppp.secret\n"
55129198Scognet#define LAUTH_M2 "Warning: All manipulation is allowed by anyone in the world\n"
56129198Scognet
57129198Scognet#ifndef O_NONBLOCK
58129198Scognet#ifdef O_NDELAY
59129198Scognet#define	O_NONBLOCK O_NDELAY
60129198Scognet#endif
61129198Scognet#endif
62129198Scognet
63129198Scognetextern void VjInit(), AsyncInit();
64129198Scognetextern void AsyncInput(), IpOutput();
65129198Scognetextern int  SelectSystem();
66129198Scognet
67129198Scognetextern void DecodeCommand(), Prompt();
68129198Scognetextern int aft_cmd;
69239268Sgonzoextern int IsInteractive();
70239268Sgonzoextern struct in_addr ifnetmask;
71239268Sgonzostatic void DoLoop(void);
72266341Sianstatic void TerminalStop();
73266341Sian
74266341Sianstatic struct termios oldtio;		/* Original tty mode */
75239268Sgonzostatic struct termios comtio;		/* Command level tty mode */
76129198Scognetint TermMode;
77129198Scognetstatic int server;
78129198Scognetstatic pid_t BGPid = 0;
79129198Scognetstruct sockaddr_in ifsin;
80129198Scognetchar pid_filename[128];
81236992Simp
82129198Scognetstatic void
83129198ScognetTtyInit()
84129198Scognet{
85129198Scognet  struct termios newtio;
86129198Scognet  int stat;
87129198Scognet
88129198Scognet  stat = fcntl(0, F_GETFL, 0);
89129198Scognet  stat |= O_NONBLOCK;
90  fcntl(0, F_SETFL, stat);
91  newtio = oldtio;
92  newtio.c_lflag &= ~(ECHO|ISIG|ICANON);
93  newtio.c_iflag = 0;
94  newtio.c_oflag &= ~OPOST;
95  newtio.c_cc[VEOF] = _POSIX_VDISABLE;
96  newtio.c_cc[VINTR] = _POSIX_VDISABLE;
97  newtio.c_cc[VMIN] = 1;
98  newtio.c_cc[VTIME] = 0;
99  newtio.c_cflag |= CS8;
100  tcsetattr(0, TCSADRAIN, &newtio);
101  comtio = newtio;
102}
103
104/*
105 *  Set tty into command mode. We allow canonical input and echo processing.
106 */
107void
108TtyCommandMode(prompt)
109int prompt;
110{
111  struct termios newtio;
112  int stat;
113
114  if (!(mode & MODE_INTER))
115    return;
116  tcgetattr(0, &newtio);
117  newtio.c_lflag |= (ECHO|ISIG|ICANON);
118  newtio.c_iflag = oldtio.c_iflag;
119  newtio.c_oflag |= OPOST;
120  tcsetattr(0, TCSADRAIN, &newtio);
121  stat = fcntl(0, F_GETFL, 0);
122  stat |= O_NONBLOCK;
123  fcntl(0, F_SETFL, stat);
124  TermMode = 0;
125  if(prompt) Prompt(0);
126}
127
128/*
129 * Set tty into terminal mode which is used while we invoke term command.
130 */
131void
132TtyTermMode()
133{
134  int stat;
135
136  tcsetattr(0, TCSADRAIN, &comtio);
137  stat = fcntl(0, F_GETFL, 0);
138  stat &= ~O_NONBLOCK;
139  fcntl(0, F_SETFL, stat);
140  TermMode = 1;
141}
142
143void
144TtyOldMode()
145{
146  int stat;
147
148  stat = fcntl(0, F_GETFL, 0);
149  stat &= ~O_NONBLOCK;
150  fcntl(0, F_SETFL, stat);
151  tcsetattr(0, TCSANOW, &oldtio);
152}
153
154void
155Cleanup(excode)
156int excode;
157{
158
159  OsLinkdown();
160  OsCloseLink(1);
161  sleep(1);
162  if (mode & (MODE_AUTO | MODE_BACKGROUND)) {
163    DeleteIfRoutes(1);
164    unlink(pid_filename);
165  }
166  OsInterfaceDown(1);
167  if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) {
168    char c = EX_ERRDEAD;
169    if (write(BGFiledes[1],&c,1) == 1)
170      LogPrintf(LOG_PHASE_BIT,"Parent notified of failure.\n");
171    else
172      LogPrintf(LOG_PHASE_BIT,"Failed to notify parent of failure.\n");
173    close(BGFiledes[1]);
174  }
175  LogPrintf(LOG_PHASE_BIT, "PPP Terminated.\n");
176  LogClose();
177  if (server >= 0) {
178    close(server);
179    server = -1;
180  }
181  TtyOldMode();
182
183  exit(excode);
184}
185
186static void
187Hangup(signo)
188int signo;
189{
190  if (signo == SIGSEGV) {
191	LogPrintf(LOG_PHASE_BIT, "Signal %d, core dump.\n", signo);
192	LogClose();
193	abort();
194  }
195  if (BGPid) {
196      kill (BGPid, SIGTERM);
197      exit (EX_HANGUP);
198  }
199  else {
200      LogPrintf(LOG_PHASE_BIT, "Signal %d, hangup.\n", signo);
201      Cleanup(EX_HANGUP);
202  }
203}
204
205static void
206CloseSession(signo)
207int signo;
208{
209   if (BGPid) {
210     kill (BGPid, SIGINT);
211     exit (EX_TERM);
212   }
213   else {
214     LogPrintf(LOG_PHASE_BIT, "Signal %d, terminate.\n", signo);
215     LcpClose();
216     Cleanup(EX_TERM);
217   }
218}
219
220static void
221TerminalCont()
222{
223  pending_signal(SIGCONT, SIG_DFL);
224  pending_signal(SIGTSTP, TerminalStop);
225  TtyCommandMode(getpgrp() == tcgetpgrp(0));
226}
227
228static void
229TerminalStop(signo)
230int signo;
231{
232  pending_signal(SIGCONT, TerminalCont);
233  TtyOldMode();
234  pending_signal(SIGTSTP, SIG_DFL);
235  kill(getpid(), signo);
236}
237
238
239void
240Usage()
241{
242  fprintf(stderr,
243          "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ] [ -alias ] [system]\n");
244  exit(EX_START);
245}
246
247void
248ProcessArgs(int argc, char **argv)
249{
250  int optc;
251  char *cp;
252
253  optc = 0;
254  while (argc > 0 && **argv == '-') {
255    cp = *argv + 1;
256    if (strcmp(cp, "auto") == 0)
257      mode |= MODE_AUTO;
258    else if (strcmp(cp, "background") == 0)
259      mode |= MODE_BACKGROUND;
260    else if (strcmp(cp, "direct") == 0)
261      mode |= MODE_DIRECT;
262    else if (strcmp(cp, "dedicated") == 0)
263      mode |= MODE_DEDICATED;
264    else if (strcmp(cp, "ddial") == 0)
265      mode |= MODE_DDIAL|MODE_AUTO;
266    else if (strcmp(cp, "alias") == 0) {
267      mode |= MODE_ALIAS;
268      optc--;             /* this option isn't exclusive */
269    }
270    else
271      Usage();
272    optc++;
273    argv++; argc--;
274  }
275  if (argc > 1) {
276    fprintf(stderr, "specify only one system label.\n");
277    exit(EX_START);
278  }
279  if (argc == 1) dstsystem = *argv;
280
281  if (optc > 1) {
282    fprintf(stderr, "specify only one mode.\n");
283    exit(EX_START);
284  }
285}
286
287static void
288Greetings()
289{
290  printf("User Process PPP. Written by Toshiharu OHNO.\r\n");
291  fflush(stdout);
292}
293
294void
295main(argc, argv)
296int argc;
297char **argv;
298{
299  int tunno;
300
301  argc--; argv++;
302
303  mode = MODE_INTER;		/* default operation is interactive mode */
304  netfd = server = modem = tun_in = -1;
305  ProcessArgs(argc, argv);
306  Greetings();
307  GetUid();
308  IpcpDefAddress();
309  InitAlias();
310
311  if (SelectSystem("default", CONFFILE) < 0) {
312    fprintf(stderr, "Warning: No default entry is given in config file.\n");
313  }
314
315  if (LogOpen())
316    exit(EX_START);
317
318  switch ( LocalAuthInit() ) {
319    case NOT_FOUND:
320    	fprintf(stderr,LAUTH_M1);
321    	fprintf(stderr,LAUTH_M2);
322	fflush (stderr);
323	/* Fall down */
324    case VALID:
325	VarLocalAuth = LOCAL_AUTH;
326	break;
327    default:
328	break;
329  }
330
331  if (OpenTunnel(&tunno) < 0) {
332    perror("open_tun");
333    exit(EX_START);
334  }
335
336  if (mode & (MODE_AUTO|MODE_DIRECT|MODE_DEDICATED|MODE_BACKGROUND))
337    mode &= ~MODE_INTER;
338  if (mode & MODE_INTER) {
339    printf("Interactive mode\n");
340    netfd = STDIN_FILENO;
341  } else if (mode & MODE_AUTO) {
342    printf("Automatic Dialer mode\n");
343    if (dstsystem == NULL) {
344      fprintf(stderr,
345              "Destination system must be specified in auto or ddial mode.\n");
346      exit(EX_START);
347    }
348  } else if (mode & MODE_BACKGROUND) {
349    printf("Background mode\n");
350    if (dstsystem == NULL) {
351      fprintf(stderr, "Destination system must be specified in background mode.\n");
352      exit(EX_START);
353    }
354  }
355
356  tcgetattr(0, &oldtio);		/* Save original tty mode */
357
358  pending_signal(SIGHUP, LogReOpen);
359  pending_signal(SIGTERM, CloseSession);
360  pending_signal(SIGINT, CloseSession);
361  pending_signal(SIGQUIT, CloseSession);
362#ifdef SIGSEGV
363  signal(SIGSEGV, Hangup);
364#endif
365#ifdef SIGPIPE
366  signal(SIGPIPE, SIG_IGN);
367#endif
368#ifdef SIGALRM
369  pending_signal(SIGALRM, SIG_IGN);
370#endif
371  if(mode & MODE_INTER)
372    {
373#ifdef SIGTSTP
374      pending_signal(SIGTSTP, TerminalStop);
375#endif
376#ifdef SIGTTIN
377      pending_signal(SIGTTIN, TerminalStop);
378#endif
379#ifdef SIGTTOU
380      pending_signal(SIGTTOU, SIG_IGN);
381#endif
382    }
383
384  if (dstsystem) {
385    if (SelectSystem(dstsystem, CONFFILE) < 0) {
386      fprintf(stderr, "Destination system not found in conf file.\n");
387      Cleanup(EX_START);
388    }
389    if ((mode & MODE_AUTO) && DefHisAddress.ipaddr.s_addr == INADDR_ANY) {
390      fprintf(stderr, "Must specify dstaddr with auto or ddial mode.\n");
391      Cleanup(EX_START);
392    }
393  }
394  if (mode & MODE_DIRECT)
395    printf("Packet mode enabled.\n");
396
397#ifdef notdef
398  if (mode & MODE_AUTO) {
399    OsSetIpaddress(IpcpInfo.want_ipaddr, IpcpInfo.his_ipaddr, ifnetmask);
400  }
401#endif
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      listen(server, 5);
430    }
431
432    DupLog();
433    if (!(mode & MODE_DIRECT)) {
434      int fd;
435      char pid[32];
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      snprintf(pid_filename, sizeof (pid_filename), "%s/ppp.tun%d.pid",
463		  _PATH_VARRUN, tunno);
464      unlink(pid_filename);
465      snprintf(pid, sizeof(pid), "%d\n", (int)getpid());
466
467      if ((fd = open(pid_filename, O_RDWR|O_CREAT, 0666)) != -1)
468      {
469	  write(fd, pid, strlen(pid));
470	  close(fd);
471      }
472    }
473    if (server >= 0)
474	LogPrintf(LOG_PHASE_BIT, "Listening at %d.\n", port);
475#ifdef DOTTYINIT
476    if (mode & (MODE_DIRECT|MODE_DEDICATED)) { /* } */
477#else
478    if (mode & MODE_DIRECT) {
479#endif
480      TtyInit();
481    } else {
482      int fd;
483
484      setsid();			/* detach control tty */
485      if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
486	(void)dup2(fd, STDIN_FILENO);
487	(void)dup2(fd, STDOUT_FILENO);
488	(void)dup2(fd, STDERR_FILENO);
489	if (fd > 2)
490		(void)close (fd);
491      }
492    }
493  } else {
494    TtyInit();
495    TtyCommandMode(1);
496  }
497  LogPrintf(LOG_PHASE_BIT, "PPP Started.\n");
498
499
500  do
501   DoLoop();
502  while (mode & MODE_DEDICATED);
503
504  Cleanup(EX_DONE);
505}
506
507/*
508 *  Turn into packet mode, where we speak PPP.
509 */
510void
511PacketMode()
512{
513  if (RawModem(modem) < 0) {
514    fprintf(stderr, "Not connected.\r\n");
515    return;
516  }
517
518  AsyncInit();
519  VjInit();
520  LcpInit();
521  IpcpInit();
522  CcpInit();
523  LcpUp();
524
525  if (mode & (MODE_DIRECT|MODE_DEDICATED))
526    LcpOpen(OPEN_ACTIVE);
527  else
528    LcpOpen(VarOpenMode);
529  if ((mode & (MODE_INTER|MODE_AUTO)) == MODE_INTER) {
530    TtyCommandMode(1);
531    fprintf(stderr, "Packet mode.\r\n");
532    aft_cmd = 1;
533  }
534}
535
536static void
537ShowHelp()
538{
539  fprintf(stderr, "The following commands are available:\r\n");
540  fprintf(stderr, " ~p\tEnter to Packet mode\r\n");
541  fprintf(stderr, " ~-\tDecrease log level\r\n");
542  fprintf(stderr, " ~+\tIncrease log level\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#define MAXLINESIZE 200
554  char linebuff[MAXLINESIZE];
555
556#ifdef DEBUG
557  logprintf("termode = %d, netfd = %d, mode = %d\n", TermMode, netfd, mode);
558#endif
559  if (!TermMode) {
560    n = read(netfd, linebuff, sizeof(linebuff)-1);
561    aft_cmd = 1;
562    if (n > 0) {
563      DecodeCommand(linebuff, n, 1);
564    } else {
565      LogPrintf(LOG_PHASE_BIT, "client connection closed.\n");
566      VarLocalAuth = LOCAL_NO_AUTH;
567      close(netfd);
568      close(1);
569      dup2(2, 1);     /* Have to have something here or the modem will be 1 */
570      netfd = -1;
571      mode &= ~MODE_INTER;
572    }
573    return;
574  }
575
576  /*
577   *  We are in terminal mode, decode special sequences
578   */
579  n = read(0, &ch, 1);
580#ifdef DEBUG
581  logprintf("got %d bytes\n", n);
582#endif
583
584  if (n > 0) {
585    switch (ttystate) {
586    case 0:
587      if (ch == '~')
588	ttystate++;
589      else
590	write(modem, &ch, n);
591      break;
592    case 1:
593      switch (ch) {
594      case '?':
595	ShowHelp();
596	break;
597      case '-':
598	if (loglevel > 0) {
599	  loglevel--;
600	  fprintf(stderr, "New loglevel is %d\r\n", loglevel);
601	}
602	break;
603      case '+':
604	loglevel++;
605	fprintf(stderr, "New loglevel is %d\r\n", loglevel);
606	break;
607#ifdef DEBUG
608      case 'm':
609	ShowMemMap();
610	break;
611#endif
612      case 'p':
613	/*
614	 * XXX: Should check carrier.
615	 */
616	if (LcpFsm.state <= ST_CLOSED) {
617	  VarOpenMode = OPEN_ACTIVE;
618	  PacketMode();
619	}
620	break;
621#ifdef DEBUG
622      case 't':
623	ShowTimers();
624	break;
625#endif
626      case '.':
627	TermMode = 1;
628	TtyCommandMode(1);
629	break;
630      default:
631	if (write(modem, &ch, n) < 0)
632	  fprintf(stderr, "err in write.\r\n");
633	break;
634      }
635      ttystate = 0;
636      break;
637    }
638  }
639}
640
641
642/*
643 *  Here, we'll try to detect HDLC frame
644 */
645
646static char *FrameHeaders[] = {
647  "\176\377\003\300\041",
648  "\176\377\175\043\300\041",
649  "\176\177\175\043\100\041",
650  "\176\175\337\175\043\300\041",
651  "\176\175\137\175\043\100\041",
652  NULL,
653};
654
655u_char *
656HdlcDetect(cp, n)
657u_char *cp;
658int n;
659{
660  char *ptr, *fp, **hp;
661
662  cp[n] = '\0';	/* be sure to null terminated */
663  ptr = NULL;
664  for (hp = FrameHeaders; *hp; hp++) {
665    fp = *hp;
666    if (DEV_IS_SYNC)
667      fp++;
668    ptr = strstr((char *)cp, fp);
669    if (ptr)
670      break;
671  }
672  return((u_char *)ptr);
673}
674
675static struct pppTimer RedialTimer;
676
677static void
678RedialTimeout()
679{
680  StopTimer(&RedialTimer);
681  LogPrintf(LOG_PHASE_BIT, "Redialing timer expired.\n");
682}
683
684static void
685StartRedialTimer()
686{
687  StopTimer(&RedialTimer);
688
689  if (VarRedialTimeout) {
690    LogPrintf(LOG_PHASE_BIT, "Enter pause for redialing.\n");
691    RedialTimer.state = TIMER_STOPPED;
692
693    if (VarRedialTimeout > 0)
694	RedialTimer.load = VarRedialTimeout * SECTICKS;
695    else
696	RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS;
697
698    RedialTimer.func = RedialTimeout;
699    StartTimer(&RedialTimer);
700  }
701}
702
703
704static void
705DoLoop()
706{
707  fd_set rfds, wfds, efds;
708  int pri, i, n, wfd, nfds;
709  struct sockaddr_in hisaddr;
710  struct timeval timeout, *tp;
711  int ssize = sizeof(hisaddr);
712  u_char *cp;
713  u_char rbuff[MAX_MRU];
714  int dial_up;
715  int tries;
716  int qlen;
717  pid_t pgroup;
718
719  pgroup = getpgrp();
720
721  if (mode & (MODE_DIRECT|MODE_BACKGROUND)) {
722    modem = OpenModem(mode);
723    LogPrintf(LOG_PHASE_BIT, "Packet mode enabled\n");
724    fflush(stderr);
725    PacketMode();
726  } else if (mode & MODE_DEDICATED) {
727    if (modem < 0)
728      modem = OpenModem(mode);
729  }
730
731  fflush(stdout);
732
733  timeout.tv_sec = 0;
734  timeout.tv_usec = 0;
735
736  if (mode & MODE_BACKGROUND)
737    dial_up = TRUE;			/* Bring the line up */
738  else
739    dial_up = FALSE;			/* XXXX */
740  tries = 0;
741  for (;;) {
742    nfds = 0;
743    FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds);
744
745    /*
746     * If the link is down and we're in DDIAL mode, bring it back
747     * up.
748     */
749    if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED)
750        dial_up = TRUE;
751
752   /*
753    * If Ip packet for output is enqueued and require dial up,
754    * Just do it!
755    */
756    if ( dial_up && RedialTimer.state != TIMER_RUNNING ) { /* XXX */
757#ifdef DEBUG
758      logprintf("going to dial: modem = %d\n", modem);
759#endif
760      modem = OpenModem(mode);
761      if (modem < 0) {
762	StartRedialTimer();
763      } else {
764	tries++;    /* Tries are per number, not per list of numbers. */
765        if (VarDialTries)
766	  LogPrintf(LOG_CHAT_BIT, "Dial attempt %u of %d\n", tries,
767		    VarDialTries);
768        else
769	  LogPrintf(LOG_CHAT_BIT, "Dial attempt %u\n", tries);
770	if (DialModem()) {
771	  sleep(1);	       /* little pause to allow peer starts */
772	  ModemTimeout();
773	  PacketMode();
774	  dial_up = FALSE;
775	  tries = 0;
776	} else {
777	  CloseModem();
778	  if (VarDialTries && tries >= VarDialTries) {
779	    /* I give up !  Can't get through :( */
780	    StartRedialTimer();
781	    dial_up = FALSE;
782	    tries = 0;
783	  } else if (VarNextPhone == NULL)
784	    /* Dial failed. Keep quite during redial wait period. */
785	    StartRedialTimer();
786	  else
787	    /*
788	     * Give the modem a chance to recover, then dial the next
789	     * number in our list
790	     */
791	    sleep(1);
792	}
793      }
794    }
795    qlen = ModemQlen();
796
797    if (qlen == 0) {
798      IpStartOutput();
799      qlen = ModemQlen();
800    }
801
802    if (modem >= 0) {
803      if (modem + 1 > nfds)
804	nfds = modem + 1;
805      FD_SET(modem, &rfds);
806      FD_SET(modem, &efds);
807      if (qlen > 0) {
808	FD_SET(modem, &wfds);
809      }
810    }
811    if (server >= 0) {
812      if (server + 1 > nfds)
813	nfds = server + 1;
814      FD_SET(server, &rfds);
815    }
816
817    /*  *** IMPORTANT ***
818     *
819     *  CPU is serviced every TICKUNIT micro seconds.
820     *	This value must be chosen with great care. If this values is
821     *  too big, it results loss of characters from modem and poor responce.
822     *  If this values is too small, ppp process eats many CPU time.
823     */
824#ifndef SIGALRM
825    usleep(TICKUNIT);
826    TimerService();
827#else
828    handle_signals();
829#endif
830
831    /* If there are aren't many packets queued, look for some more. */
832    if (qlen < 20 && tun_in >= 0) {
833      if (tun_in + 1 > nfds)
834	nfds = tun_in + 1;
835      FD_SET(tun_in, &rfds);
836    }
837
838    if (netfd >= 0) {
839      if (netfd + 1 > nfds)
840	nfds = netfd + 1;
841      FD_SET(netfd, &rfds);
842      FD_SET(netfd, &efds);
843    }
844
845#ifndef SIGALRM
846    /*
847     *  Normally, select() will not block because modem is writable.
848     *  In AUTO mode, select will block until we find packet from tun
849     */
850    tp = (RedialTimer.state == TIMER_RUNNING)? &timeout : NULL;
851    i = select(nfds, &rfds, &wfds, &efds, tp);
852#else
853    /*
854     * When SIGALRM timer is running, a select function will be
855     * return -1 and EINTR after a Time Service signal hundler
856     * is done.  If the redial timer is not running and we are
857     * trying to dial, poll with a 0 value timer.
858     */
859    tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL;
860    i = select(nfds, &rfds, &wfds, &efds, tp);
861#endif
862
863    if ( i == 0 ) {
864        continue;
865    }
866
867    if ( i < 0 ) {
868       if ( errno == EINTR ) {
869          handle_signals();
870          continue;
871       }
872       perror("select");
873       break;
874    }
875
876    if ((netfd >= 0 && FD_ISSET(netfd, &efds)) || (modem >= 0 && FD_ISSET(modem, &efds))) {
877      logprintf("Exception detected.\n");
878      break;
879    }
880
881    if (server >= 0 && FD_ISSET(server, &rfds)) {
882      LogPrintf(LOG_PHASE_BIT, "connected to client.\n");
883      wfd = accept(server, (struct sockaddr *)&hisaddr, &ssize);
884      if (wfd < 0) {
885	perror("accept");
886	continue;
887      }
888      if (netfd >= 0) {
889	write(wfd, "already in use.\n", 16);
890	close(wfd);
891	continue;
892      } else
893	netfd = wfd;
894      if (dup2(netfd, 1) < 0) {
895	perror("dup2");
896	close(netfd);
897	netfd = -1;
898	continue;
899      }
900      mode |= MODE_INTER;
901      Greetings();
902      switch ( LocalAuthInit() ) {
903         case NOT_FOUND:
904    	    fprintf(stdout,LAUTH_M1);
905    	    fprintf(stdout,LAUTH_M2);
906            fflush(stdout);
907	    /* Fall down */
908         case VALID:
909	    VarLocalAuth = LOCAL_AUTH;
910	    break;
911         default:
912	    break;
913      }
914      (void) IsInteractive();
915      Prompt(0);
916    }
917
918    if ((mode & MODE_INTER) && (netfd >= 0 && FD_ISSET(netfd, &rfds)) &&
919	((mode & MODE_AUTO) || pgroup == tcgetpgrp(0))) {
920      /* something to read from tty */
921      ReadTty();
922    }
923    if (modem >= 0) {
924      if (FD_ISSET(modem, &wfds)) {	/* ready to write into modem */
925	 ModemStartOutput(modem);
926      }
927      if (FD_ISSET(modem, &rfds)) {	/* something to read from modem */
928	if (LcpFsm.state <= ST_CLOSED)
929	  usleep(10000);
930	n = read(modem, rbuff, sizeof(rbuff));
931	if ((mode & MODE_DIRECT) && n <= 0) {
932	  DownConnection();
933	} else
934          LogDumpBuff(LOG_ASYNC, "ReadFromModem", rbuff, n);
935
936	if (LcpFsm.state <= ST_CLOSED) {
937	  /*
938	   *  In dedicated mode, we just discard input until LCP is started.
939	   */
940	  if (!(mode & MODE_DEDICATED)) {
941	    cp = HdlcDetect(rbuff, n);
942	    if (cp) {
943	      /*
944	       * LCP packet is detected. Turn ourselves into packet mode.
945	       */
946	      if (cp != rbuff) {
947	        write(1, rbuff, cp - rbuff);
948	        write(1, "\r\n", 2);
949	      }
950	      PacketMode();
951#ifdef notdef
952	      AsyncInput(cp, n - (cp - rbuff));
953#endif
954	    } else
955	      write(1, rbuff, n);
956	  }
957	} else {
958	  if (n > 0)
959	    AsyncInput(rbuff, n);
960#ifdef notdef
961	  continue;			/* THIS LINE RESULT AS POOR PERFORMANCE */
962#endif
963	}
964      }
965    }
966
967    if (tun_in >= 0 && FD_ISSET(tun_in, &rfds)) {       /* something to read from tun */
968      n = read(tun_in, rbuff, sizeof(rbuff));
969      if (n < 0) {
970	perror("read from tun");
971	continue;
972      }
973      /*
974       *  Process on-demand dialup. Output packets are queued within tunnel
975       *  device until IPCP is opened.
976       */
977      if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) {
978	pri = PacketCheck(rbuff, n, FL_DIAL);
979	if (pri >= 0) {
980	  if (mode & MODE_ALIAS) {
981	    PacketAliasOut((struct ip *)rbuff);
982	    n = ntohs(((struct ip *)rbuff)->ip_len);
983	  }
984	  IpEnqueue(pri, rbuff, n);
985	  dial_up = TRUE;		/* XXX */
986	}
987	continue;
988      }
989      pri = PacketCheck(rbuff, n, FL_OUT);
990      if (pri >= 0) {
991        if (mode & MODE_ALIAS) {
992          PacketAliasOut((struct ip *)rbuff);
993          n = ntohs(((struct ip *)rbuff)->ip_len);
994        }
995	IpEnqueue(pri, rbuff, n);
996      }
997    }
998  }
999  logprintf("job done.\n");
1000}
1001