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