main.c revision 22997
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$
21 *
22 *	TODO:
23 *		o Add commands for traffic summary, version display, etc.
24 *		o Add signal handler for misc controls.
25 */
26#include "fsm.h"
27#include <fcntl.h>
28#include <paths.h>
29#include <sys/time.h>
30#include <termios.h>
31#include "sig.h"
32#include <sys/wait.h>
33#include <errno.h>
34#include <netdb.h>
35#include <unistd.h>
36#include <sys/socket.h>
37#include <arpa/inet.h>
38#include <netinet/in_systm.h>
39#include <netinet/ip.h>
40#include "modem.h"
41#include "os.h"
42#include "hdlc.h"
43#include "ccp.h"
44#include "lcp.h"
45#include "ipcp.h"
46#include "vars.h"
47#include "auth.h"
48#include "filter.h"
49#include "systems.h"
50#include "ip.h"
51#include "alias.h"
52
53#define LAUTH_M1 "Warning: No password entry for this host in ppp.secret\n"
54#define LAUTH_M2 "Warning: All manipulation is allowed by anyone in the world\n"
55
56#ifndef O_NONBLOCK
57#ifdef O_NDELAY
58#define	O_NONBLOCK O_NDELAY
59#endif
60#endif
61
62extern void VjInit(), AsyncInit();
63extern void AsyncInput(), IpOutput();
64extern int  SelectSystem();
65
66extern void DecodeCommand(), Prompt();
67extern int aft_cmd;
68extern int IsInteractive();
69extern struct in_addr ifnetmask;
70static void DoLoop(void);
71static void TerminalStop();
72
73static struct termios oldtio;		/* Original tty mode */
74static struct termios comtio;		/* Command level tty mode */
75int TermMode;
76static int server;
77static pid_t BGPid = 0;
78struct sockaddr_in ifsin;
79char pid_filename[128];
80
81static void
82TtyInit()
83{
84  struct termios newtio;
85  int stat;
86
87  stat = fcntl(0, F_GETFL, 0);
88  stat |= O_NONBLOCK;
89  fcntl(0, F_SETFL, stat);
90  newtio = oldtio;
91  newtio.c_lflag &= ~(ECHO|ISIG|ICANON);
92  newtio.c_iflag = 0;
93  newtio.c_oflag &= ~OPOST;
94  newtio.c_cc[VEOF] = _POSIX_VDISABLE;
95  newtio.c_cc[VINTR] = _POSIX_VDISABLE;
96  newtio.c_cc[VMIN] = 1;
97  newtio.c_cc[VTIME] = 0;
98  newtio.c_cflag |= CS8;
99  tcsetattr(0, TCSADRAIN, &newtio);
100  comtio = newtio;
101}
102
103/*
104 *  Set tty into command mode. We allow canonical input and echo processing.
105 */
106void
107TtyCommandMode(prompt)
108int prompt;
109{
110  struct termios newtio;
111  int stat;
112
113  if (!(mode & MODE_INTER))
114    return;
115  tcgetattr(0, &newtio);
116  newtio.c_lflag |= (ECHO|ISIG|ICANON);
117  newtio.c_iflag = oldtio.c_iflag;
118  newtio.c_oflag |= OPOST;
119  tcsetattr(0, TCSADRAIN, &newtio);
120  stat = fcntl(0, F_GETFL, 0);
121  stat |= O_NONBLOCK;
122  fcntl(0, F_SETFL, stat);
123  TermMode = 0;
124  if(prompt) Prompt(0);
125}
126
127/*
128 * Set tty into terminal mode which is used while we invoke term command.
129 */
130void
131TtyTermMode()
132{
133  int stat;
134
135  tcsetattr(0, TCSADRAIN, &comtio);
136  stat = fcntl(0, F_GETFL, 0);
137  stat &= ~O_NONBLOCK;
138  fcntl(0, F_SETFL, stat);
139  TermMode = 1;
140}
141
142void
143TtyOldMode()
144{
145  int stat;
146
147  stat = fcntl(0, F_GETFL, 0);
148  stat &= ~O_NONBLOCK;
149  fcntl(0, F_SETFL, stat);
150  tcsetattr(0, TCSANOW, &oldtio);
151}
152
153void
154Cleanup(excode)
155int excode;
156{
157
158  OsLinkdown();
159  OsCloseLink(1);
160  sleep(1);
161  if (mode & MODE_AUTO) {
162    DeleteIfRoutes(1);
163  }
164  if (mode & (MODE_AUTO | MODE_BACKGROUND)) {
165    unlink(pid_filename);
166  }
167  OsInterfaceDown(1);
168  LogPrintf(LOG_PHASE_BIT, "PPP Terminated.\n");
169  LogClose();
170  if (server > 0)
171    close(server);
172  TtyOldMode();
173
174  exit(excode);
175}
176
177static void
178Hangup(signo)
179int signo;
180{
181  if (signo == SIGSEGV) {
182	LogPrintf(LOG_PHASE_BIT, "Signal %d, core dump.\n", signo);
183	LogClose();
184	abort();
185  }
186  if (BGPid) {
187      kill (BGPid, SIGHUP);
188      exit (EX_HANGUP);
189  }
190  else {
191      LogPrintf(LOG_PHASE_BIT, "Signal %d, hangup.\n", signo);
192      Cleanup(EX_HANGUP);
193  }
194}
195
196static void
197CloseSession(signo)
198int signo;
199{
200   if (BGPid) {
201     kill (BGPid, SIGINT);
202     exit (EX_TERM);
203   }
204   else {
205     LogPrintf(LOG_PHASE_BIT, "Signal %d, terminate.\n", signo);
206     LcpClose();
207     Cleanup(EX_TERM);
208   }
209}
210
211static void
212TerminalCont()
213{
214  pending_signal(SIGCONT, SIG_DFL);
215  pending_signal(SIGTSTP, TerminalStop);
216  TtyCommandMode(getpgrp() == tcgetpgrp(0));
217}
218
219static void
220TerminalStop(signo)
221int signo;
222{
223  pending_signal(SIGCONT, TerminalCont);
224  TtyOldMode();
225  pending_signal(SIGTSTP, SIG_DFL);
226  kill(getpid(), signo);
227}
228
229
230void
231Usage()
232{
233  fprintf(stderr,
234          "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ] [ -alias ] [system]\n");
235  exit(EX_START);
236}
237
238void
239ProcessArgs(int argc, char **argv)
240{
241  int optc;
242  char *cp;
243
244  optc = 0;
245  while (argc > 0 && **argv == '-') {
246    cp = *argv + 1;
247    if (strcmp(cp, "auto") == 0)
248      mode |= MODE_AUTO;
249    else if (strcmp(cp, "background") == 0)
250      mode |= MODE_BACKGROUND;
251    else if (strcmp(cp, "direct") == 0)
252      mode |= MODE_DIRECT;
253    else if (strcmp(cp, "dedicated") == 0)
254      mode |= MODE_DEDICATED;
255    else if (strcmp(cp, "ddial") == 0)
256      mode |= MODE_DDIAL|MODE_AUTO;
257    else if (strcmp(cp, "alias") == 0) {
258      mode |= MODE_ALIAS;
259      optc--;             /* this option isn't exclusive */
260    }
261    else
262      Usage();
263    optc++;
264    argv++; argc--;
265  }
266  if (argc > 1) {
267    fprintf(stderr, "specify only one system label.\n");
268    exit(EX_START);
269  }
270  if (argc == 1) dstsystem = *argv;
271
272  if (optc > 1) {
273    fprintf(stderr, "specify only one mode.\n");
274    exit(EX_START);
275  }
276}
277
278static void
279Greetings()
280{
281  printf("User Process PPP. Written by Toshiharu OHNO.\r\n");
282  fflush(stdout);
283}
284
285void
286main(argc, argv)
287int argc;
288char **argv;
289{
290  int tunno;
291
292  argc--; argv++;
293
294  mode = MODE_INTER;		/* default operation is interactive mode */
295  netfd = -1;
296  ProcessArgs(argc, argv);
297  Greetings();
298  GetUid();
299  IpcpDefAddress();
300  InitAlias();
301
302  if (SelectSystem("default", CONFFILE) < 0) {
303    fprintf(stderr, "Warning: No default entry is given in config file.\n");
304  }
305
306  if (LogOpen())
307    exit(EX_START);
308
309  switch ( LocalAuthInit() ) {
310    case NOT_FOUND:
311    	fprintf(stderr,LAUTH_M1);
312    	fprintf(stderr,LAUTH_M2);
313	fflush (stderr);
314	/* Fall down */
315    case VALID:
316	VarLocalAuth = LOCAL_AUTH;
317	break;
318    default:
319	break;
320  }
321
322  if (OpenTunnel(&tunno) < 0) {
323    perror("open_tun");
324    exit(EX_START);
325  }
326
327  if (mode & (MODE_AUTO|MODE_DIRECT|MODE_DEDICATED|MODE_BACKGROUND))
328    mode &= ~MODE_INTER;
329  if (mode & MODE_INTER) {
330    printf("Interactive mode\n");
331    netfd = 0;
332  } else if (mode & MODE_AUTO) {
333    printf("Automatic Dialer mode\n");
334    if (dstsystem == NULL) {
335      fprintf(stderr,
336              "Destination system must be specified in auto or ddial mode.\n");
337      exit(EX_START);
338    }
339  } else if (mode & MODE_BACKGROUND) {
340    printf("Background mode\n");
341    if (dstsystem == NULL) {
342      fprintf(stderr, "Destination system must be specified in background mode.\n");
343      exit(EX_START);
344    }
345  }
346
347  tcgetattr(0, &oldtio);		/* Save original tty mode */
348
349  pending_signal(SIGHUP, Hangup);
350  pending_signal(SIGTERM, CloseSession);
351  pending_signal(SIGINT, CloseSession);
352  pending_signal(SIGQUIT, CloseSession);
353#ifdef SIGSEGV
354  pending_signal(SIGSEGV, Hangup);
355#endif
356#ifdef SIGPIPE
357  pending_signal(SIGPIPE, Hangup);
358#endif
359#ifdef SIGALRM
360  pending_signal(SIGALRM, SIG_IGN);
361#endif
362  if(mode & MODE_INTER)
363    {
364#ifdef SIGTSTP
365      pending_signal(SIGTSTP, TerminalStop);
366#endif
367#ifdef SIGTTIN
368      pending_signal(SIGTTIN, TerminalStop);
369#endif
370#ifdef SIGTTOU
371      pending_signal(SIGTTOU, SIG_IGN);
372#endif
373    }
374
375  if (dstsystem) {
376    if (SelectSystem(dstsystem, CONFFILE) < 0) {
377      fprintf(stderr, "Destination system not found in conf file.\n");
378      Cleanup(EX_START);
379    }
380    if ((mode & MODE_AUTO) && DefHisAddress.ipaddr.s_addr == INADDR_ANY) {
381      fprintf(stderr, "Must specify dstaddr with auto or ddial mode.\n");
382      Cleanup(EX_START);
383    }
384  }
385  if (mode & MODE_DIRECT)
386    printf("Packet mode enabled.\n");
387
388#ifdef notdef
389  if (mode & MODE_AUTO) {
390    OsSetIpaddress(IpcpInfo.want_ipaddr, IpcpInfo.his_ipaddr, ifnetmask);
391  }
392#endif
393
394  if (!(mode & MODE_INTER)) {
395    int port = SERVER_PORT + tunno;
396    if (mode & MODE_BACKGROUND) {
397      if (pipe (BGFiledes)) {
398	perror("pipe");
399	Cleanup(EX_SOCK);
400      }
401      server = -1;
402    }
403    else {
404      /*
405       *  Create server socket and listen at there.
406       */
407      server = socket(PF_INET, SOCK_STREAM, 0);
408      if (server < 0) {
409	perror("socket");
410	Cleanup(EX_SOCK);
411      }
412      ifsin.sin_family = AF_INET;
413      ifsin.sin_addr.s_addr = INADDR_ANY;
414      ifsin.sin_port = htons(port);
415      if (bind(server, (struct sockaddr *) &ifsin, sizeof(ifsin)) < 0) {
416	perror("bind");
417	if (errno == EADDRINUSE)
418	  fprintf(stderr, "Wait for a while, then try again.\n");
419	Cleanup(EX_SOCK);
420      }
421      listen(server, 5);
422    }
423
424    DupLog();
425    if (!(mode & MODE_DIRECT)) {
426      int fd;
427      char pid[32];
428      pid_t bgpid;
429
430      bgpid = fork ();
431      if (bgpid == -1) {
432	perror ("fork");
433	Cleanup (EX_SOCK);
434      }
435      if (bgpid) {
436	char c = EX_NORMAL;
437
438	if (mode & MODE_BACKGROUND) {
439	  /* Wait for our child to close its pipe before we exit. */
440	  BGPid = bgpid;
441	  read (BGFiledes[0], &c, 1);
442	  if (c == EX_NORMAL)
443	    LogPrintf (LOG_CHAT, "PPP enabled.\n");
444	}
445        exit(c);
446      }
447
448      snprintf(pid_filename, sizeof (pid_filename), "%s/ppp.tun%d.pid",
449		  _PATH_VARRUN, tunno);
450      unlink(pid_filename);
451      snprintf(pid, sizeof(pid), "%d\n", (int)getpid());
452
453      if ((fd = open(pid_filename, O_RDWR|O_CREAT, 0666)) != -1)
454      {
455	  write(fd, pid, strlen(pid));
456	  close(fd);
457      }
458    }
459    if (server > 0)
460	LogPrintf(LOG_PHASE_BIT, "Listening at %d.\n", port);
461#ifdef DOTTYINIT
462    if (mode & (MODE_DIRECT|MODE_DEDICATED)) { /* } */
463#else
464    if (mode & MODE_DIRECT) {
465#endif
466      TtyInit();
467    } else {
468      int fd;
469
470      setsid();			/* detach control tty */
471      if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
472	(void)dup2(fd, STDIN_FILENO);
473	(void)dup2(fd, STDOUT_FILENO);
474	(void)dup2(fd, STDERR_FILENO);
475	if (fd > 2)
476		(void)close (fd);
477      }
478    }
479  } else {
480    server = -1;
481    TtyInit();
482    TtyCommandMode(1);
483  }
484  LogPrintf(LOG_PHASE_BIT, "PPP Started.\n");
485
486
487  do
488   DoLoop();
489  while (mode & MODE_DEDICATED);
490
491  Cleanup(EX_DONE);
492}
493
494/*
495 *  Turn into packet mode, where we speak PPP.
496 */
497void
498PacketMode()
499{
500  if (RawModem(modem) < 0) {
501    fprintf(stderr, "Not connected.\r\n");
502    return;
503  }
504
505  AsyncInit();
506  VjInit();
507  LcpInit();
508  IpcpInit();
509  CcpInit();
510  LcpUp();
511
512  if (mode & (MODE_DIRECT|MODE_DEDICATED))
513    LcpOpen(OPEN_ACTIVE);
514  else
515    LcpOpen(VarOpenMode);
516  if ((mode & (MODE_INTER|MODE_AUTO)) == MODE_INTER) {
517    TtyCommandMode(1);
518    fprintf(stderr, "Packet mode.\r\n");
519    aft_cmd = 1;
520  }
521}
522
523static void
524ShowHelp()
525{
526  fprintf(stderr, "The following commands are available:\r\n");
527  fprintf(stderr, " ~p\tEnter to Packet mode\r\n");
528  fprintf(stderr, " ~-\tDecrease log level\r\n");
529  fprintf(stderr, " ~+\tIncrease log level\r\n");
530  fprintf(stderr, " ~.\tTerminate program\r\n");
531  fprintf(stderr, " ~?\tThis help\r\n");
532}
533
534static void
535ReadTty()
536{
537  int n;
538  char ch;
539  static int ttystate;
540#define MAXLINESIZE 200
541  char linebuff[MAXLINESIZE];
542
543#ifdef DEBUG
544  logprintf("termode = %d, netfd = %d, mode = %d\n", TermMode, netfd, mode);
545#endif
546  if (!TermMode) {
547    n = read(netfd, linebuff, sizeof(linebuff)-1);
548    aft_cmd = 1;
549    if (n > 0) {
550      DecodeCommand(linebuff, n, 1);
551    } else {
552#ifdef DEBUG
553      logprintf("connection closed.\n");
554#endif
555      close(netfd);
556      netfd = -1;
557      mode &= ~MODE_INTER;
558    }
559    return;
560  }
561
562  /*
563   *  We are in terminal mode, decode special sequences
564   */
565  n = read(0, &ch, 1);
566#ifdef DEBUG
567  logprintf("got %d bytes\n", n);
568#endif
569
570  if (n > 0) {
571    switch (ttystate) {
572    case 0:
573      if (ch == '~')
574	ttystate++;
575      else
576	write(modem, &ch, n);
577      break;
578    case 1:
579      switch (ch) {
580      case '?':
581	ShowHelp();
582	break;
583      case '-':
584	if (loglevel > 0) {
585	  loglevel--;
586	  fprintf(stderr, "New loglevel is %d\r\n", loglevel);
587	}
588	break;
589      case '+':
590	loglevel++;
591	fprintf(stderr, "New loglevel is %d\r\n", loglevel);
592	break;
593#ifdef DEBUG
594      case 'm':
595	ShowMemMap();
596	break;
597#endif
598      case 'p':
599	/*
600	 * XXX: Should check carrier.
601	 */
602	if (LcpFsm.state <= ST_CLOSED) {
603	  VarOpenMode = OPEN_ACTIVE;
604	  PacketMode();
605	}
606	break;
607#ifdef DEBUG
608      case 't':
609	ShowTimers();
610	break;
611#endif
612      case '.':
613	TermMode = 1;
614	TtyCommandMode(1);
615	break;
616      default:
617	if (write(modem, &ch, n) < 0)
618	  fprintf(stderr, "err in write.\r\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
641u_char *
642HdlcDetect(cp, n)
643u_char *cp;
644int n;
645{
646  char *ptr, *fp, **hp;
647
648  cp[n] = '\0';	/* be sure to null terminated */
649  ptr = NULL;
650  for (hp = FrameHeaders; *hp; hp++) {
651    fp = *hp;
652    if (DEV_IS_SYNC)
653      fp++;
654    ptr = strstr((char *)cp, fp);
655    if (ptr)
656      break;
657  }
658  return((u_char *)ptr);
659}
660
661static struct pppTimer RedialTimer;
662
663static void
664RedialTimeout()
665{
666  StopTimer(&RedialTimer);
667  LogPrintf(LOG_PHASE_BIT, "Redialing timer expired.\n");
668}
669
670static void
671StartRedialTimer()
672{
673  StopTimer(&RedialTimer);
674
675  if (VarRedialTimeout) {
676    LogPrintf(LOG_PHASE_BIT, "Enter pause for redialing.\n");
677    RedialTimer.state = TIMER_STOPPED;
678
679    if (VarRedialTimeout > 0)
680	RedialTimer.load = VarRedialTimeout * SECTICKS;
681    else
682	RedialTimer.load = (random() % REDIAL_PERIOD) * 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;
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 dial_up;
701  int tries;
702  int qlen;
703  pid_t pgroup;
704
705  pgroup = getpgrp();
706
707  if (mode & MODE_DIRECT) {
708    modem = OpenModem(mode);
709    LogPrintf(LOG_PHASE_BIT, "Packet mode enabled\n");
710    fflush(stderr);
711    PacketMode();
712  } else if (mode & MODE_DEDICATED) {
713    if (!modem)
714      modem = OpenModem(mode);
715  }
716
717  fflush(stdout);
718
719  timeout.tv_sec = 0;
720  timeout.tv_usec = 0;
721
722  dial_up = FALSE;			/* XXXX */
723  tries = 0;
724  for (;;) {
725    FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds);
726
727    /*
728     * If the link is down and we're in DDIAL mode, bring it back
729     * up.
730     */
731    if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED)
732        dial_up = TRUE;
733
734   /*
735    * If Ip packet for output is enqueued and require dial up,
736    * Just do it!
737    */
738    if ( dial_up && RedialTimer.state != TIMER_RUNNING ) { /* XXX */
739#ifdef DEBUG
740      logprintf("going to dial: modem = %d\n", modem);
741#endif
742      modem = OpenModem(mode);
743      if (modem < 0) {
744	modem = 0;	       /* Set intial value for next OpenModem */
745	StartRedialTimer();
746      } else {
747	tries++;
748	LogPrintf(LOG_CHAT_BIT, "Dial attempt %u\n", tries);
749	if (DialModem()) {
750	  sleep(1);	       /* little pause to allow peer starts */
751	  ModemTimeout();
752	  PacketMode();
753	  dial_up = FALSE;
754	  tries = 0;
755	} else {
756	  CloseModem();
757	  /* Dial failed. Keep quite during redial wait period. */
758	  StartRedialTimer();
759
760	  if (VarDialTries && tries >= VarDialTries) {
761	      dial_up = FALSE;
762	      tries = 0;
763	  }
764	}
765      }
766    }
767    qlen = ModemQlen();
768
769    if (qlen == 0) {
770      IpStartOutput();
771      qlen = ModemQlen();
772    }
773
774    if (modem) {
775      FD_SET(modem, &rfds);
776      FD_SET(modem, &efds);
777      if (qlen > 0) {
778	FD_SET(modem, &wfds);
779      }
780    }
781    if (server > 0) FD_SET(server, &rfds);
782
783    /*  *** IMPORTANT ***
784     *
785     *  CPU is serviced every TICKUNIT micro seconds.
786     *	This value must be chosen with great care. If this values is
787     *  too big, it results loss of characters from modem and poor responce.
788     *  If this values is too small, ppp process eats many CPU time.
789     */
790#ifndef SIGALRM
791    usleep(TICKUNIT);
792    TimerService();
793#else
794    handle_signals();
795#endif
796
797    /* If there are aren't many packets queued, look for some more. */
798    if (qlen < 20)
799      FD_SET(tun_in, &rfds);
800
801    if (netfd > -1) {
802      FD_SET(netfd, &rfds);
803      FD_SET(netfd, &efds);
804    }
805
806#ifndef SIGALRM
807    /*
808     *  Normally, select() will not block because modem is writable.
809     *  In AUTO mode, select will block until we find packet from tun
810     */
811    tp = (RedialTimer.state == TIMER_RUNNING)? &timeout : NULL;
812    i = select(tun_in+10, &rfds, &wfds, &efds, tp);
813#else
814    /*
815     * When SIGALRM timer is running, a select function will be
816     * return -1 and EINTR after a Time Service signal hundler
817     * is done.  If the redial timer is not running and we are
818     * trying to dial, poll with a 0 value timer.
819     */
820    tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL;
821    i = select(tun_in+10, &rfds, &wfds, &efds, tp);
822#endif
823
824    if ( i == 0 ) {
825        continue;
826    }
827
828    if ( i < 0 ) {
829       if ( errno == EINTR ) {
830          handle_signals();
831          continue;
832       }
833       perror("select");
834       break;
835    }
836
837    if ((netfd > 0 && FD_ISSET(netfd, &efds)) || FD_ISSET(modem, &efds)) {
838      logprintf("Exception detected.\n");
839      break;
840    }
841
842    if (server > 0 && FD_ISSET(server, &rfds)) {
843#ifdef DEBUG
844      logprintf("connected to client.\n");
845#endif
846      wfd = accept(server, (struct sockaddr *)&hisaddr, &ssize);
847      if (netfd > 0) {
848	write(wfd, "already in use.\n", 16);
849	close(wfd);
850	continue;
851      } else
852	netfd = wfd;
853      if (dup2(netfd, 1) < 0)
854	perror("dup2");
855      mode |= MODE_INTER;
856      Greetings();
857      switch ( LocalAuthInit() ) {
858         case NOT_FOUND:
859    	    fprintf(stdout,LAUTH_M1);
860    	    fprintf(stdout,LAUTH_M2);
861            fflush(stdout);
862	    /* Fall down */
863         case VALID:
864	    VarLocalAuth = LOCAL_AUTH;
865	    break;
866         default:
867	    break;
868      }
869      (void) IsInteractive();
870      Prompt(0);
871    }
872
873    if ((mode & MODE_INTER) && FD_ISSET(netfd, &rfds) &&
874	((mode & MODE_AUTO) || pgroup == tcgetpgrp(0))) {
875      /* something to read from tty */
876      ReadTty();
877    }
878    if (modem) {
879      if (FD_ISSET(modem, &wfds)) {	/* ready to write into modem */
880	 ModemStartOutput(modem);
881      }
882      if (FD_ISSET(modem, &rfds)) {	/* something to read from modem */
883	if (LcpFsm.state <= ST_CLOSED)
884	  usleep(10000);
885	n = read(modem, rbuff, sizeof(rbuff));
886	if ((mode & MODE_DIRECT) && n <= 0) {
887	  DownConnection();
888	} else
889          LogDumpBuff(LOG_ASYNC, "ReadFromModem", rbuff, n);
890
891	if (LcpFsm.state <= ST_CLOSED) {
892	  /*
893	   *  In dedicated mode, we just discard input until LCP is started.
894	   */
895	  if (!(mode & MODE_DEDICATED)) {
896	    cp = HdlcDetect(rbuff, n);
897	    if (cp) {
898	      /*
899	       * LCP packet is detected. Turn ourselves into packet mode.
900	       */
901	      if (cp != rbuff) {
902	        write(1, rbuff, cp - rbuff);
903	        write(1, "\r\n", 2);
904	      }
905	      PacketMode();
906#ifdef notdef
907	      AsyncInput(cp, n - (cp - rbuff));
908#endif
909	    } else
910	      write(1, rbuff, n);
911	  }
912	} else {
913	  if (n > 0)
914	    AsyncInput(rbuff, n);
915#ifdef notdef
916	  continue;			/* THIS LINE RESULT AS POOR PERFORMANCE */
917#endif
918	}
919      }
920    }
921
922    if (FD_ISSET(tun_in, &rfds)) {	/* something to read from tun */
923      n = read(tun_in, rbuff, sizeof(rbuff));
924      if (n < 0) {
925	perror("read from tun");
926	continue;
927      }
928      /*
929       *  Process on-demand dialup. Output packets are queued within tunnel
930       *  device until IPCP is opened.
931       */
932      if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) {
933	pri = PacketCheck(rbuff, n, FL_DIAL);
934	if (pri >= 0) {
935	  if (mode & MODE_ALIAS) {
936	    PacketAliasOut((struct ip *)rbuff);
937	    n = ntohs(((struct ip *)rbuff)->ip_len);
938	  }
939	  IpEnqueue(pri, rbuff, n);
940	  dial_up = TRUE;		/* XXX */
941	}
942	continue;
943      }
944      pri = PacketCheck(rbuff, n, FL_OUT);
945      if (pri >= 0) {
946        if (mode & MODE_ALIAS) {
947          PacketAliasOut((struct ip *)rbuff);
948          n = ntohs(((struct ip *)rbuff)->ip_len);
949        }
950	IpEnqueue(pri, rbuff, n);
951      }
952    }
953  }
954  logprintf("job done.\n");
955}
956