main.c revision 32860
16059Samurai/*
26059Samurai *			User Process PPP
36059Samurai *
46059Samurai *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
56059Samurai *
66059Samurai *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
76059Samurai *
86059Samurai * Redistribution and use in source and binary forms are permitted
96059Samurai * provided that the above copyright notice and this paragraph are
106059Samurai * duplicated in all such forms and that any documentation,
116059Samurai * advertising materials, and other materials related to such
126059Samurai * distribution and use acknowledge that the software was developed
136059Samurai * by the Internet Initiative Japan, Inc.  The name of the
146059Samurai * IIJ may not be used to endorse or promote products derived
156059Samurai * from this software without specific prior written permission.
166059Samurai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
176059Samurai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
186059Samurai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
196059Samurai *
2032860Sbrian * $Id: main.c,v 1.120 1998/01/27 23:14:51 brian Exp $
218857Srgrimes *
226059Samurai *	TODO:
236059Samurai *		o Add commands for traffic summary, version display, etc.
246059Samurai *		o Add signal handler for misc controls.
256059Samurai */
2630715Sbrian#include <sys/param.h>
2731195Sbrian#include <sys/time.h>
2831195Sbrian#include <sys/select.h>
2930715Sbrian#include <sys/socket.h>
3032663Sbrian#include <net/if.h>
3132663Sbrian#include <net/if_tun.h>
3230715Sbrian#include <netinet/in.h>
3330715Sbrian#include <netinet/in_systm.h>
3430715Sbrian#include <netinet/ip.h>
3530715Sbrian#include <arpa/inet.h>
3630715Sbrian
3730715Sbrian#include <errno.h>
386059Samurai#include <fcntl.h>
3911336Samurai#include <paths.h>
4030715Sbrian#include <signal.h>
4130715Sbrian#include <stdio.h>
4230715Sbrian#include <stdlib.h>
4330715Sbrian#include <string.h>
446059Samurai#include <sys/time.h>
4530715Sbrian#include <sys/wait.h>
466059Samurai#include <termios.h>
4718786Sjkh#include <unistd.h>
4830715Sbrian
4931343Sbrian#include "command.h"
5030715Sbrian#include "mbuf.h"
5130715Sbrian#include "log.h"
5230715Sbrian#include "defs.h"
5331061Sbrian#include "id.h"
5430715Sbrian#include "timer.h"
5530715Sbrian#include "fsm.h"
566059Samurai#include "modem.h"
576059Samurai#include "os.h"
586059Samurai#include "hdlc.h"
5931514Sbrian#include "lcp.h"
6013389Sphk#include "ccp.h"
616059Samurai#include "ipcp.h"
6226142Sbrian#include "loadalias.h"
636059Samurai#include "vars.h"
646735Samurai#include "auth.h"
657001Samurai#include "filter.h"
6613389Sphk#include "systems.h"
6713389Sphk#include "ip.h"
6823840Sbrian#include "sig.h"
6926940Sbrian#include "server.h"
7030715Sbrian#include "main.h"
7130715Sbrian#include "vjcomp.h"
7230715Sbrian#include "async.h"
7331158Sbrian#include "pathnames.h"
7431195Sbrian#include "tun.h"
7531343Sbrian#include "route.h"
766059Samurai
776735Samurai#ifndef O_NONBLOCK
786735Samurai#ifdef O_NDELAY
796735Samurai#define	O_NONBLOCK O_NDELAY
806735Samurai#endif
816735Samurai#endif
826735Samurai
8330715Sbrianint TermMode = 0;
8430715Sbrianint tunno = 0;
856059Samurai
8628679Sbrianstatic struct termios oldtio;	/* Original tty mode */
8728679Sbrianstatic struct termios comtio;	/* Command level tty mode */
8820813Sjkhstatic pid_t BGPid = 0;
8925634Sbrianstatic char pid_filename[MAXPATHLEN];
9027061Sbrianstatic int dial_up;
916059Samurai
9230715Sbrianstatic void DoLoop(void);
9330715Sbrianstatic void TerminalStop(int);
9431343Sbrianstatic const char *ex_desc(int);
9530715Sbrian
966059Samuraistatic void
9726858SbrianTtyInit(int DontWantInt)
986059Samurai{
996059Samurai  struct termios newtio;
1006059Samurai  int stat;
1016059Samurai
10232129Sbrian  stat = fcntl(netfd, F_GETFL, 0);
10325630Sbrian  if (stat > 0) {
10428679Sbrian    stat |= O_NONBLOCK;
10532129Sbrian    (void) fcntl(netfd, F_SETFL, stat);
10625630Sbrian  }
1076059Samurai  newtio = oldtio;
10828679Sbrian  newtio.c_lflag &= ~(ECHO | ISIG | ICANON);
1096059Samurai  newtio.c_iflag = 0;
1106059Samurai  newtio.c_oflag &= ~OPOST;
1116059Samurai  newtio.c_cc[VEOF] = _POSIX_VDISABLE;
11226858Sbrian  if (DontWantInt)
11326858Sbrian    newtio.c_cc[VINTR] = _POSIX_VDISABLE;
1146059Samurai  newtio.c_cc[VMIN] = 1;
1156059Samurai  newtio.c_cc[VTIME] = 0;
1166059Samurai  newtio.c_cflag |= CS8;
11732129Sbrian  tcsetattr(netfd, TCSANOW, &newtio);
1186059Samurai  comtio = newtio;
1196059Samurai}
1206059Samurai
1216059Samurai/*
1226059Samurai *  Set tty into command mode. We allow canonical input and echo processing.
1236059Samurai */
12410528Samuraivoid
12528679SbrianTtyCommandMode(int prompt)
1266059Samurai{
1276059Samurai  struct termios newtio;
1286059Samurai  int stat;
1296059Samurai
1306059Samurai  if (!(mode & MODE_INTER))
1316059Samurai    return;
13232129Sbrian  tcgetattr(netfd, &newtio);
13328679Sbrian  newtio.c_lflag |= (ECHO | ISIG | ICANON);
1346059Samurai  newtio.c_iflag = oldtio.c_iflag;
1356059Samurai  newtio.c_oflag |= OPOST;
13632129Sbrian  tcsetattr(netfd, TCSADRAIN, &newtio);
13732129Sbrian  stat = fcntl(netfd, F_GETFL, 0);
13825630Sbrian  if (stat > 0) {
13928679Sbrian    stat |= O_NONBLOCK;
14032129Sbrian    (void) fcntl(netfd, F_SETFL, stat);
14125630Sbrian  }
1426059Samurai  TermMode = 0;
14328679Sbrian  if (prompt)
14428679Sbrian    Prompt();
1456059Samurai}
1466059Samurai
1476059Samurai/*
1486059Samurai * Set tty into terminal mode which is used while we invoke term command.
1496059Samurai */
1506059Samuraivoid
1516059SamuraiTtyTermMode()
1526059Samurai{
1536059Samurai  int stat;
1546059Samurai
15532129Sbrian  tcsetattr(netfd, TCSADRAIN, &comtio);
15632129Sbrian  stat = fcntl(netfd, F_GETFL, 0);
15725630Sbrian  if (stat > 0) {
15828679Sbrian    stat &= ~O_NONBLOCK;
15932129Sbrian    (void) fcntl(netfd, F_SETFL, stat);
16025630Sbrian  }
1616059Samurai  TermMode = 1;
1626059Samurai}
1636059Samurai
1646059Samuraivoid
16510528SamuraiTtyOldMode()
1666059Samurai{
1676059Samurai  int stat;
1686059Samurai
16932129Sbrian  stat = fcntl(netfd, F_GETFL, 0);
17025630Sbrian  if (stat > 0) {
17128679Sbrian    stat &= ~O_NONBLOCK;
17232129Sbrian    (void) fcntl(netfd, F_SETFL, stat);
17325630Sbrian  }
17432129Sbrian  tcsetattr(netfd, TCSADRAIN, &oldtio);
17510528Samurai}
17610528Samurai
17710528Samuraivoid
17828679SbrianCleanup(int excode)
17910528Samurai{
18032021Sbrian  DropClient(1);
18131081Sbrian  ServerClose();
18230825Sbrian  OsInterfaceDown(1);
18330825Sbrian  HangupModem(1);
18430697Sbrian  nointr_sleep(1);
18531121Sbrian  DeleteIfRoutes(1);
18631061Sbrian  ID0unlink(pid_filename);
18723863Sbrian  if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) {
18823863Sbrian    char c = EX_ERRDEAD;
18928679Sbrian
19028679Sbrian    if (write(BGFiledes[1], &c, 1) == 1)
19128679Sbrian      LogPrintf(LogPHASE, "Parent notified of failure.\n");
19223863Sbrian    else
19328679Sbrian      LogPrintf(LogPHASE, "Failed to notify parent of failure.\n");
19423863Sbrian    close(BGFiledes[1]);
19523863Sbrian  }
19628679Sbrian  LogPrintf(LogPHASE, "PPP Terminated (%s).\n", ex_desc(excode));
19710528Samurai  TtyOldMode();
19831061Sbrian  LogClose();
1996059Samurai
2006059Samurai  exit(excode);
2016059Samurai}
2026059Samurai
2036059Samuraistatic void
20428679SbrianCloseConnection(int signo)
2056059Samurai{
20626858Sbrian  /* NOTE, these are manual, we've done a setsid() */
20731121Sbrian  pending_signal(SIGINT, SIG_IGN);
20827157Sbrian  LogPrintf(LogPHASE, "Caught signal %d, abort connection\n", signo);
20928679Sbrian  reconnectState = RECON_FALSE;
21028684Sbrian  reconnectCount = 0;
21128684Sbrian  DownConnection();
21230715Sbrian  dial_up = 0;
21331121Sbrian  pending_signal(SIGINT, CloseConnection);
2146059Samurai}
2156059Samurai
2166059Samuraistatic void
21728679SbrianCloseSession(int signo)
2186059Samurai{
21928679Sbrian  if (BGPid) {
22028679Sbrian    kill(BGPid, SIGINT);
22128679Sbrian    exit(EX_TERM);
22228679Sbrian  }
22328679Sbrian  LogPrintf(LogPHASE, "Signal %d, terminate.\n", signo);
22428679Sbrian  reconnect(RECON_FALSE);
22528679Sbrian  LcpClose();
22628679Sbrian  Cleanup(EX_TERM);
2276059Samurai}
2286059Samurai
22910528Samuraistatic void
23031343SbrianTerminalCont(int signo)
23110528Samurai{
23223840Sbrian  pending_signal(SIGCONT, SIG_DFL);
23323840Sbrian  pending_signal(SIGTSTP, TerminalStop);
23432129Sbrian  TtyCommandMode(getpgrp() == tcgetpgrp(netfd));
23510528Samurai}
23610528Samurai
23710528Samuraistatic void
23828679SbrianTerminalStop(int signo)
23910528Samurai{
24023840Sbrian  pending_signal(SIGCONT, TerminalCont);
24110528Samurai  TtyOldMode();
24223840Sbrian  pending_signal(SIGTSTP, SIG_DFL);
24310528Samurai  kill(getpid(), signo);
24410528Samurai}
24510528Samurai
24626940Sbrianstatic void
24728679SbrianSetUpServer(int signo)
24826940Sbrian{
24926940Sbrian  int res;
25028679Sbrian
25131081Sbrian  VarHaveLocalAuthKey = 0;
25231081Sbrian  LocalAuthInit();
25328679Sbrian  if ((res = ServerTcpOpen(SERVER_PORT + tunno)) != 0)
25429083Sbrian    LogPrintf(LogERROR, "SIGUSR1: Failed %d to open port %d\n",
25529083Sbrian	      res, SERVER_PORT + tunno);
25626940Sbrian}
25726940Sbrian
25831081Sbrianstatic void
25931081SbrianBringDownServer(int signo)
26031081Sbrian{
26131081Sbrian  VarHaveLocalAuthKey = 0;
26231081Sbrian  LocalAuthInit();
26331081Sbrian  ServerClose();
26431081Sbrian}
26531081Sbrian
26631343Sbrianstatic const char *
26725908Sbrianex_desc(int ex)
26825908Sbrian{
26925908Sbrian  static char num[12];
27031343Sbrian  static const char *desc[] = {
27131343Sbrian    "normal", "start", "sock", "modem", "dial", "dead", "done",
27231343Sbrian    "reboot", "errdead", "hangup", "term", "nodial", "nologin"
27331343Sbrian  };
27410528Samurai
27531962Sbrian  if (ex >= 0 && ex < sizeof desc / sizeof *desc)
27625908Sbrian    return desc[ex];
27725908Sbrian  snprintf(num, sizeof num, "%d", ex);
27825908Sbrian  return num;
27925908Sbrian}
28025908Sbrian
28130715Sbrianstatic void
28231343SbrianUsage(void)
2836059Samurai{
28420120Snate  fprintf(stderr,
28531343Sbrian	  "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ]"
28631343Sbrian#ifndef NOALIAS
28731343Sbrian          " [ -alias ]"
28831343Sbrian#endif
28931343Sbrian          " [system]\n");
2906059Samurai  exit(EX_START);
2916059Samurai}
2926059Samurai
29331197Sbrianstatic char *
2946059SamuraiProcessArgs(int argc, char **argv)
2956059Samurai{
2966059Samurai  int optc;
2976059Samurai  char *cp;
2986059Samurai
2996059Samurai  optc = 0;
30031121Sbrian  mode = MODE_INTER;
3016059Samurai  while (argc > 0 && **argv == '-') {
3026059Samurai    cp = *argv + 1;
30331121Sbrian    if (strcmp(cp, "auto") == 0) {
3046059Samurai      mode |= MODE_AUTO;
30531121Sbrian      mode &= ~MODE_INTER;
30631121Sbrian    } else if (strcmp(cp, "background") == 0) {
30731121Sbrian      mode |= MODE_BACKGROUND;
30831121Sbrian      mode &= ~MODE_INTER;
30931121Sbrian    } else if (strcmp(cp, "direct") == 0) {
3106059Samurai      mode |= MODE_DIRECT;
31131121Sbrian      mode &= ~MODE_INTER;
31231121Sbrian    } else if (strcmp(cp, "dedicated") == 0) {
3136059Samurai      mode |= MODE_DEDICATED;
31431121Sbrian      mode &= ~MODE_INTER;
31531121Sbrian    } else if (strcmp(cp, "ddial") == 0) {
31631121Sbrian      mode |= MODE_DDIAL;
31731121Sbrian      mode &= ~MODE_INTER;
31831343Sbrian#ifndef NOALIAS
31931121Sbrian    } else if (strcmp(cp, "alias") == 0) {
32026142Sbrian      if (loadAliasHandlers(&VarAliasHandlers) == 0)
32128679Sbrian	mode |= MODE_ALIAS;
32226142Sbrian      else
32328679Sbrian	LogPrintf(LogWARN, "Cannot load alias library\n");
32428679Sbrian      optc--;			/* this option isn't exclusive */
32531343Sbrian#endif
32628679Sbrian    } else
3276059Samurai      Usage();
3286059Samurai    optc++;
32928679Sbrian    argv++;
33028679Sbrian    argc--;
3316059Samurai  }
3326059Samurai  if (argc > 1) {
3336059Samurai    fprintf(stderr, "specify only one system label.\n");
3346059Samurai    exit(EX_START);
3356059Samurai  }
3366059Samurai
3376059Samurai  if (optc > 1) {
3386059Samurai    fprintf(stderr, "specify only one mode.\n");
3396059Samurai    exit(EX_START);
3406059Samurai  }
34131197Sbrian
34231197Sbrian  return argc == 1 ? *argv : NULL;	/* Don't SetLabel yet ! */
3436059Samurai}
3446059Samurai
34526940Sbrianint
34628679Sbrianmain(int argc, char **argv)
3476059Samurai{
34825707Sbrian  FILE *lockfile;
34931197Sbrian  char *name, *label;
35031823Sbrian  int nfds;
35126516Sbrian
35231823Sbrian  nfds = getdtablesize();
35331823Sbrian  if (nfds >= FD_SETSIZE)
35431823Sbrian    /*
35531823Sbrian     * If we've got loads of file descriptors, make sure they're all
35631823Sbrian     * closed.  If they aren't, we may end up with a seg fault when our
35731823Sbrian     * `fd_set's get too big when select()ing !
35831823Sbrian     */
35931823Sbrian    while (--nfds > 2)
36031823Sbrian      close(nfds);
36131823Sbrian
36226551Sbrian  VarTerm = 0;
36330715Sbrian  name = strrchr(argv[0], '/');
36428679Sbrian  LogOpen(name ? name + 1 : argv[0]);
36526516Sbrian
36632129Sbrian  tcgetattr(STDIN_FILENO, &oldtio);	/* Save original tty mode */
36732129Sbrian
36828679Sbrian  argc--;
36928679Sbrian  argv++;
37031197Sbrian  label = ProcessArgs(argc, argv);
37131121Sbrian  if (!(mode & MODE_DIRECT))
37226551Sbrian    VarTerm = stdout;
37331121Sbrian
37431121Sbrian  ID0init();
37531158Sbrian  if (ID0realuid() != 0) {
37631158Sbrian    char conf[200], *ptr;
37731158Sbrian
37831158Sbrian    snprintf(conf, sizeof conf, "%s/%s", _PATH_PPP, CONFFILE);
37931158Sbrian    do {
38031158Sbrian      if (!access(conf, W_OK)) {
38131158Sbrian        LogPrintf(LogALERT, "ppp: Access violation: Please protect %s\n", conf);
38231158Sbrian        return -1;
38331158Sbrian      }
38431158Sbrian      ptr = conf + strlen(conf)-2;
38531158Sbrian      while (ptr > conf && *ptr != '/')
38631158Sbrian        *ptr-- = '\0';
38731158Sbrian    } while (ptr >= conf);
38831158Sbrian  }
38931158Sbrian
39031197Sbrian  if (!ValidSystem(label)) {
39131121Sbrian    fprintf(stderr, "You may not use ppp in this mode with this label\n");
39231157Sbrian    if (mode & MODE_DIRECT) {
39331157Sbrian      const char *l;
39431197Sbrian      l = label ? label : "default";
39531157Sbrian      LogPrintf(LogWARN, "Label %s rejected -direct connection\n", l);
39631157Sbrian    }
39731157Sbrian    LogClose();
39831121Sbrian    return 1;
39929083Sbrian  }
40031121Sbrian
40131196Sbrian  if (!GetShortHost())
40231196Sbrian    return 1;
40332833Sbrian  IsInteractive(1);
4046059Samurai  IpcpDefAddress();
4056059Samurai
40631285Sbrian  if (mode & MODE_INTER)
40731285Sbrian    VarLocalAuth = LOCAL_AUTH;
40831285Sbrian
40926516Sbrian  if (SelectSystem("default", CONFFILE) < 0 && VarTerm)
41026516Sbrian    fprintf(VarTerm, "Warning: No default entry is given in config file.\n");
4116059Samurai
4126059Samurai  if (OpenTunnel(&tunno) < 0) {
41331690Sbrian    LogPrintf(LogWARN, "OpenTunnel: %s\n", strerror(errno));
41426940Sbrian    return EX_START;
4156059Samurai  }
41632351Sbrian  CleanInterface(IfDevName);
41732833Sbrian  if ((mode & MODE_OUTGOING_DAEMON) && !(mode & MODE_DEDICATED))
41831197Sbrian    if (label == NULL) {
41926516Sbrian      if (VarTerm)
42028679Sbrian	fprintf(VarTerm, "Destination system must be specified in"
42128679Sbrian		" auto, background or ddial mode.\n");
42226940Sbrian      return EX_START;
4236059Samurai    }
42431121Sbrian
42527157Sbrian  pending_signal(SIGHUP, CloseSession);
42623840Sbrian  pending_signal(SIGTERM, CloseSession);
42727157Sbrian  pending_signal(SIGINT, CloseConnection);
42823840Sbrian  pending_signal(SIGQUIT, CloseSession);
4296735Samurai#ifdef SIGPIPE
43024753Sache  signal(SIGPIPE, SIG_IGN);
4316735Samurai#endif
4326735Samurai#ifdef SIGALRM
43323840Sbrian  pending_signal(SIGALRM, SIG_IGN);
4346735Samurai#endif
43528679Sbrian  if (mode & MODE_INTER) {
43610528Samurai#ifdef SIGTSTP
43726940Sbrian    pending_signal(SIGTSTP, TerminalStop);
43810528Samurai#endif
43910528Samurai#ifdef SIGTTIN
44026940Sbrian    pending_signal(SIGTTIN, TerminalStop);
44110528Samurai#endif
44210528Samurai#ifdef SIGTTOU
44326940Sbrian    pending_signal(SIGTTOU, SIG_IGN);
44410528Samurai#endif
44526940Sbrian  }
44631121Sbrian  if (!(mode & MODE_INTER)) {
44726940Sbrian#ifdef SIGUSR1
44826940Sbrian    pending_signal(SIGUSR1, SetUpServer);
44926940Sbrian#endif
45031081Sbrian#ifdef SIGUSR2
45131081Sbrian    pending_signal(SIGUSR2, BringDownServer);
45231081Sbrian#endif
45331121Sbrian  }
4546059Samurai
45531197Sbrian  if (label) {
45631197Sbrian    if (SelectSystem(label, CONFFILE) < 0) {
45731154Sbrian      LogPrintf(LogWARN, "Destination system %s not found in conf file.\n",
45831154Sbrian                GetLabel());
4596059Samurai      Cleanup(EX_START);
4606059Samurai    }
46131197Sbrian    /*
46231197Sbrian     * We don't SetLabel() 'till now in case SelectSystem() has an
46331197Sbrian     * embeded load "otherlabel" command.
46431197Sbrian     */
46531197Sbrian    SetLabel(label);
46631121Sbrian    if (mode & MODE_OUTGOING_DAEMON &&
46731121Sbrian	DefHisAddress.ipaddr.s_addr == INADDR_ANY) {
46831154Sbrian      LogPrintf(LogWARN, "You must \"set ifaddr\" in label %s for"
46931197Sbrian		" auto, background or ddial mode.\n", label);
4706059Samurai      Cleanup(EX_START);
4716059Samurai    }
4726059Samurai  }
47326940Sbrian
47431121Sbrian  if (mode & MODE_DAEMON) {
47520813Sjkh    if (mode & MODE_BACKGROUND) {
47628679Sbrian      if (pipe(BGFiledes)) {
47728974Sbrian	LogPrintf(LogERROR, "pipe: %s\n", strerror(errno));
47820813Sjkh	Cleanup(EX_SOCK);
47920813Sjkh      }
4806059Samurai    }
4816059Samurai
4826059Samurai    if (!(mode & MODE_DIRECT)) {
48320813Sjkh      pid_t bgpid;
48411336Samurai
48528679Sbrian      bgpid = fork();
48620813Sjkh      if (bgpid == -1) {
48728974Sbrian	LogPrintf(LogERROR, "fork: %s\n", strerror(errno));
48828679Sbrian	Cleanup(EX_SOCK);
48920813Sjkh      }
49020813Sjkh      if (bgpid) {
49120813Sjkh	char c = EX_NORMAL;
49211336Samurai
49320813Sjkh	if (mode & MODE_BACKGROUND) {
49420813Sjkh	  /* Wait for our child to close its pipe before we exit. */
49520813Sjkh	  BGPid = bgpid;
49628679Sbrian	  close(BGFiledes[1]);
49725908Sbrian	  if (read(BGFiledes[0], &c, 1) != 1) {
49826516Sbrian	    fprintf(VarTerm, "Child exit, no status.\n");
49928679Sbrian	    LogPrintf(LogPHASE, "Parent: Child exit, no status.\n");
50025908Sbrian	  } else if (c == EX_NORMAL) {
50126516Sbrian	    fprintf(VarTerm, "PPP enabled.\n");
50228679Sbrian	    LogPrintf(LogPHASE, "Parent: PPP enabled.\n");
50325908Sbrian	  } else {
50428679Sbrian	    fprintf(VarTerm, "Child failed (%s).\n", ex_desc((int) c));
50526516Sbrian	    LogPrintf(LogPHASE, "Parent: Child failed (%s).\n",
50628679Sbrian		      ex_desc((int) c));
50728679Sbrian	  }
50828679Sbrian	  close(BGFiledes[0]);
50920813Sjkh	}
51028679Sbrian	return c;
51123863Sbrian      } else if (mode & MODE_BACKGROUND)
51228679Sbrian	close(BGFiledes[0]);
51325707Sbrian    }
51420813Sjkh
51528679Sbrian    VarTerm = 0;		/* We know it's currently stdout */
51632129Sbrian    close(STDOUT_FILENO);
51732129Sbrian    close(STDERR_FILENO);
51826551Sbrian
51926686Sbrian    if (mode & MODE_DIRECT)
52032129Sbrian      /* STDIN_FILENO gets used by OpenModem in DIRECT mode */
52126858Sbrian      TtyInit(1);
52231121Sbrian    else if (mode & MODE_DAEMON) {
52326686Sbrian      setsid();
52432129Sbrian      close(STDIN_FILENO);
52526686Sbrian    }
5266059Samurai  } else {
52732129Sbrian    close(STDIN_FILENO);
52832129Sbrian    if ((netfd = open(_PATH_TTY, O_RDONLY)) < 0) {
52932129Sbrian      fprintf(stderr, "Cannot open %s for intput !\n", _PATH_TTY);
53032129Sbrian      return 2;
53132129Sbrian    }
53232129Sbrian    close(STDERR_FILENO);
53326858Sbrian    TtyInit(0);
53410528Samurai    TtyCommandMode(1);
5356059Samurai  }
53629696Sbrian
53731962Sbrian  snprintf(pid_filename, sizeof pid_filename, "%stun%d.pid",
53829696Sbrian           _PATH_VARRUN, tunno);
53931061Sbrian  lockfile = ID0fopen(pid_filename, "w");
54031061Sbrian  if (lockfile != NULL) {
54129696Sbrian    fprintf(lockfile, "%d\n", (int) getpid());
54229696Sbrian    fclose(lockfile);
54332860Sbrian  }
54432860Sbrian#ifndef RELEASE_CRUNCH
54532860Sbrian  else
54629696Sbrian    LogPrintf(LogALERT, "Warning: Can't create %s: %s\n",
54729696Sbrian              pid_filename, strerror(errno));
54832860Sbrian#endif
54929696Sbrian
55026516Sbrian  LogPrintf(LogPHASE, "PPP Started.\n");
5516059Samurai
5526059Samurai
5536059Samurai  do
55428679Sbrian    DoLoop();
5556059Samurai  while (mode & MODE_DEDICATED);
5566059Samurai
5576059Samurai  Cleanup(EX_DONE);
55826940Sbrian  return 0;
5596059Samurai}
5606059Samurai
5616059Samurai/*
56220813Sjkh *  Turn into packet mode, where we speak PPP.
5636059Samurai */
5646059Samuraivoid
56532658SbrianPacketMode(int delay)
5666059Samurai{
56731034Sbrian  if (RawModem() < 0) {
56826516Sbrian    LogPrintf(LogWARN, "PacketMode: Not connected.\n");
5696059Samurai    return;
5706059Samurai  }
5716059Samurai  AsyncInit();
57230187Sbrian  VjInit(15);
5736059Samurai  LcpInit();
5746059Samurai  IpcpInit();
5756059Samurai  CcpInit();
5766059Samurai  LcpUp();
5776059Samurai
57832658Sbrian  LcpOpen(delay);
57931121Sbrian  if (mode & MODE_INTER)
58010528Samurai    TtyCommandMode(1);
58131121Sbrian  if (VarTerm) {
58231121Sbrian    fprintf(VarTerm, "Packet mode.\n");
58331121Sbrian    aft_cmd = 1;
5846059Samurai  }
5856059Samurai}
5866059Samurai
5876059Samuraistatic void
58831343SbrianShowHelp(void)
5896059Samurai{
59026901Sbrian  fprintf(stderr, "The following commands are available:\r\n");
59126901Sbrian  fprintf(stderr, " ~p\tEnter Packet mode\r\n");
59226901Sbrian  fprintf(stderr, " ~-\tDecrease log level\r\n");
59326901Sbrian  fprintf(stderr, " ~+\tIncrease log level\r\n");
59426901Sbrian  fprintf(stderr, " ~t\tShow timers (only in \"log debug\" mode)\r\n");
59526901Sbrian  fprintf(stderr, " ~m\tShow memory map (only in \"log debug\" mode)\r\n");
59626901Sbrian  fprintf(stderr, " ~.\tTerminate program\r\n");
59726901Sbrian  fprintf(stderr, " ~?\tThis help\r\n");
5986059Samurai}
5996059Samurai
6006059Samuraistatic void
60131343SbrianReadTty(void)
6026059Samurai{
6036059Samurai  int n;
6046059Samurai  char ch;
6056059Samurai  static int ttystate;
60631070Sbrian  char linebuff[LINE_LEN];
60728679Sbrian
60826516Sbrian  LogPrintf(LogDEBUG, "termode = %d, netfd = %d, mode = %d\n",
60928679Sbrian	    TermMode, netfd, mode);
6106059Samurai  if (!TermMode) {
61131962Sbrian    n = read(netfd, linebuff, sizeof linebuff - 1);
6126735Samurai    if (n > 0) {
61326516Sbrian      aft_cmd = 1;
61430913Sbrian      if (linebuff[n-1] == '\n')
61530913Sbrian        linebuff[--n] = '\0';
61631962Sbrian      else
61731962Sbrian        linebuff[n] = '\0';
61831156Sbrian      if (n)
61931156Sbrian        DecodeCommand(linebuff, n, IsInteractive(0) ? NULL : "Client");
62031156Sbrian      Prompt();
62132021Sbrian    } else if (n <= 0) {
62232021Sbrian      LogPrintf(LogPHASE, "Client connection closed.\n");
62332021Sbrian      DropClient(0);
62432021Sbrian    }
6256059Samurai    return;
6266059Samurai  }
6276059Samurai
6286059Samurai  /*
62928679Sbrian   * We are in terminal mode, decode special sequences
6306059Samurai   */
63132129Sbrian  n = read(netfd, &ch, 1);
63228974Sbrian  LogPrintf(LogDEBUG, "Got %d bytes (reading from the terminal)\n", n);
6336059Samurai
6346059Samurai  if (n > 0) {
6356059Samurai    switch (ttystate) {
6366059Samurai    case 0:
6376059Samurai      if (ch == '~')
6386059Samurai	ttystate++;
6396059Samurai      else
6406059Samurai	write(modem, &ch, n);
6416059Samurai      break;
6426059Samurai    case 1:
6436059Samurai      switch (ch) {
6446059Samurai      case '?':
6456059Samurai	ShowHelp();
6466059Samurai	break;
6476059Samurai      case 'p':
64828679Sbrian
6496059Samurai	/*
6506059Samurai	 * XXX: Should check carrier.
6516059Samurai	 */
65232658Sbrian	if (LcpFsm.state <= ST_CLOSED)
65332658Sbrian	  PacketMode(0);
6546059Samurai	break;
6556059Samurai      case '.':
6566059Samurai	TermMode = 1;
65726516Sbrian	aft_cmd = 1;
65810528Samurai	TtyCommandMode(1);
6596059Samurai	break;
66026516Sbrian      case 't':
66126516Sbrian	if (LogIsKept(LogDEBUG)) {
66226516Sbrian	  ShowTimers();
66326516Sbrian	  break;
66426516Sbrian	}
66526516Sbrian      case 'm':
66626516Sbrian	if (LogIsKept(LogDEBUG)) {
66731343Sbrian	  ShowMemMap(NULL);
66826516Sbrian	  break;
66926516Sbrian	}
6706059Samurai      default:
6716059Samurai	if (write(modem, &ch, n) < 0)
67226516Sbrian	  LogPrintf(LogERROR, "error writing to modem.\n");
6736059Samurai	break;
6746059Samurai      }
6756059Samurai      ttystate = 0;
6766059Samurai      break;
6776059Samurai    }
6786059Samurai  }
6796059Samurai}
6806059Samurai
6816059Samurai
6826059Samurai/*
6836059Samurai *  Here, we'll try to detect HDLC frame
6846059Samurai */
6856059Samurai
68631343Sbrianstatic const char *FrameHeaders[] = {
6876735Samurai  "\176\377\003\300\041",
6886735Samurai  "\176\377\175\043\300\041",
6896735Samurai  "\176\177\175\043\100\041",
6906735Samurai  "\176\175\337\175\043\300\041",
6916735Samurai  "\176\175\137\175\043\100\041",
6926059Samurai  NULL,
6936059Samurai};
6946059Samurai
69531343Sbrianstatic const u_char *
69628679SbrianHdlcDetect(u_char * cp, int n)
6976059Samurai{
69831343Sbrian  const char *ptr, *fp, **hp;
6996059Samurai
70028679Sbrian  cp[n] = '\0';			/* be sure to null terminated */
7016059Samurai  ptr = NULL;
7026059Samurai  for (hp = FrameHeaders; *hp; hp++) {
7036735Samurai    fp = *hp;
7046735Samurai    if (DEV_IS_SYNC)
7056735Samurai      fp++;
70628679Sbrian    ptr = strstr((char *) cp, fp);
70713389Sphk    if (ptr)
7086059Samurai      break;
7096059Samurai  }
71031343Sbrian  return ((const u_char *) ptr);
7116059Samurai}
7126059Samurai
7136059Samuraistatic struct pppTimer RedialTimer;
7146059Samurai
7156059Samuraistatic void
71631343SbrianRedialTimeout(void *v)
7176059Samurai{
7186059Samurai  StopTimer(&RedialTimer);
71926516Sbrian  LogPrintf(LogPHASE, "Redialing timer expired.\n");
7206059Samurai}
7216059Samurai
7226059Samuraistatic void
72328679SbrianStartRedialTimer(int Timeout)
7246059Samurai{
7256059Samurai  StopTimer(&RedialTimer);
72611336Samurai
72724939Sbrian  if (Timeout) {
72811336Samurai    RedialTimer.state = TIMER_STOPPED;
72911336Samurai
73024939Sbrian    if (Timeout > 0)
73128679Sbrian      RedialTimer.load = Timeout * SECTICKS;
73211336Samurai    else
73328679Sbrian      RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS;
73411336Samurai
73526516Sbrian    LogPrintf(LogPHASE, "Enter pause (%d) for redialing.\n",
73624939Sbrian	      RedialTimer.load / SECTICKS);
73724939Sbrian
73811336Samurai    RedialTimer.func = RedialTimeout;
73911336Samurai    StartTimer(&RedialTimer);
74011336Samurai  }
7416059Samurai}
7426059Samurai
74331825Sbrian#define IN_SIZE sizeof(struct sockaddr_in)
74431825Sbrian#define UN_SIZE sizeof(struct sockaddr_in)
74531825Sbrian#define ADDRSZ (IN_SIZE > UN_SIZE ? IN_SIZE : UN_SIZE)
7466059Samurai
7476059Samuraistatic void
74831343SbrianDoLoop(void)
7496059Samurai{
7506059Samurai  fd_set rfds, wfds, efds;
75123598Sache  int pri, i, n, wfd, nfds;
75231825Sbrian  char hisaddr[ADDRSZ];
75331825Sbrian  struct sockaddr *sa = (struct sockaddr *)hisaddr;
75431825Sbrian  struct sockaddr_in *sin = (struct sockaddr_in *)hisaddr;
7556059Samurai  struct timeval timeout, *tp;
75631825Sbrian  int ssize = ADDRSZ;
75731343Sbrian  const u_char *cp;
75811336Samurai  int tries;
7599448Samurai  int qlen;
76026858Sbrian  int res;
76131195Sbrian  struct tun_data tun;
76231195Sbrian#define rbuff tun.data
7636059Samurai
76425908Sbrian  if (mode & MODE_DIRECT) {
76526551Sbrian    LogPrintf(LogDEBUG, "Opening modem\n");
76631034Sbrian    if (OpenModem() < 0)
76729521Sbrian      return;
76826516Sbrian    LogPrintf(LogPHASE, "Packet mode enabled\n");
76932658Sbrian    PacketMode(VarOpenMode);
7706059Samurai  } else if (mode & MODE_DEDICATED) {
77123598Sache    if (modem < 0)
77231034Sbrian      while (OpenModem() < 0)
77330697Sbrian	nointr_sleep(VarReconnectTimer);
7746059Samurai  }
77526516Sbrian  fflush(VarTerm);
7766059Samurai
7777001Samurai  timeout.tv_sec = 0;
7786059Samurai  timeout.tv_usec = 0;
77926098Sbrian  reconnectState = RECON_UNKNOWN;
7806059Samurai
78123863Sbrian  if (mode & MODE_BACKGROUND)
78230715Sbrian    dial_up = 1;		/* Bring the line up */
78323863Sbrian  else
78430715Sbrian    dial_up = 0;		/* XXXX */
78511336Samurai  tries = 0;
7866059Samurai  for (;;) {
78723598Sache    nfds = 0;
78828679Sbrian    FD_ZERO(&rfds);
78928679Sbrian    FD_ZERO(&wfds);
79028679Sbrian    FD_ZERO(&efds);
7917001Samurai
79228679Sbrian    /*
79328679Sbrian     * If the link is down and we're in DDIAL mode, bring it back up.
79420120Snate     */
79520120Snate    if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED)
79630715Sbrian      dial_up = 1;
79720120Snate
79825067Sbrian    /*
79928679Sbrian     * If we lost carrier and want to re-establish the connection due to the
80028679Sbrian     * "set reconnect" value, we'd better bring the line back up.
80125067Sbrian     */
80225908Sbrian    if (LcpFsm.state <= ST_CLOSED) {
80330715Sbrian      if (!dial_up && reconnectState == RECON_TRUE) {
80428679Sbrian	if (++reconnectCount <= VarReconnectTries) {
80528679Sbrian	  LogPrintf(LogPHASE, "Connection lost, re-establish (%d/%d)\n",
80628679Sbrian		    reconnectCount, VarReconnectTries);
80725908Sbrian	  StartRedialTimer(VarReconnectTimer);
80830715Sbrian	  dial_up = 1;
80928679Sbrian	} else {
81028679Sbrian	  if (VarReconnectTries)
81128679Sbrian	    LogPrintf(LogPHASE, "Connection lost, maximum (%d) times\n",
81228679Sbrian		      VarReconnectTries);
81328679Sbrian	  reconnectCount = 0;
81428679Sbrian	  if (mode & MODE_BACKGROUND)
81528679Sbrian	    Cleanup(EX_DEAD);
81628679Sbrian	}
81728679Sbrian	reconnectState = RECON_ENVOKED;
81831121Sbrian      } else if (mode & MODE_DEDICATED)
81932658Sbrian        PacketMode(VarOpenMode);
82025908Sbrian    }
82125067Sbrian
82228679Sbrian    /*
82328679Sbrian     * If Ip packet for output is enqueued and require dial up, Just do it!
82428679Sbrian     */
82528679Sbrian    if (dial_up && RedialTimer.state != TIMER_RUNNING) {
82626516Sbrian      LogPrintf(LogDEBUG, "going to dial: modem = %d\n", modem);
82731034Sbrian      if (OpenModem() < 0) {
82828679Sbrian	tries++;
82928679Sbrian	if (!(mode & MODE_DDIAL) && VarDialTries)
83028679Sbrian	  LogPrintf(LogCHAT, "Failed to open modem (attempt %u of %d)\n",
83128679Sbrian		    tries, VarDialTries);
83228679Sbrian	else
83328679Sbrian	  LogPrintf(LogCHAT, "Failed to open modem (attempt %u)\n", tries);
83426551Sbrian
83526696Sbrian	if (!(mode & MODE_DDIAL) && VarDialTries && tries >= VarDialTries) {
83626551Sbrian	  if (mode & MODE_BACKGROUND)
83728679Sbrian	    Cleanup(EX_DIAL);	/* Can't get the modem */
83830715Sbrian	  dial_up = 0;
83928679Sbrian	  reconnectState = RECON_UNKNOWN;
84028679Sbrian	  reconnectCount = 0;
84126551Sbrian	  tries = 0;
84228679Sbrian	} else
84326551Sbrian	  StartRedialTimer(VarRedialTimeout);
84411336Samurai      } else {
84528679Sbrian	tries++;		/* Tries are per number, not per list of
84628679Sbrian				 * numbers. */
84728679Sbrian	if (!(mode & MODE_DDIAL) && VarDialTries)
84826696Sbrian	  LogPrintf(LogCHAT, "Dial attempt %u of %d\n", tries, VarDialTries);
84928679Sbrian	else
85028679Sbrian	  LogPrintf(LogCHAT, "Dial attempt %u\n", tries);
85126696Sbrian
85226858Sbrian	if ((res = DialModem()) == EX_DONE) {
85331343Sbrian	  ModemTimeout(NULL);
85432658Sbrian	  PacketMode(VarOpenMode);
85530715Sbrian	  dial_up = 0;
85628679Sbrian	  reconnectState = RECON_UNKNOWN;
85711336Samurai	  tries = 0;
85811336Samurai	} else {
85924844Sbrian	  if (mode & MODE_BACKGROUND) {
86026858Sbrian	    if (VarNextPhone == NULL || res == EX_SIG)
86128679Sbrian	      Cleanup(EX_DIAL);	/* Tried all numbers - no luck */
86224844Sbrian	    else
86324939Sbrian	      /* Try all numbers in background mode */
86424939Sbrian	      StartRedialTimer(VarRedialNextTimeout);
86526858Sbrian	  } else if (!(mode & MODE_DDIAL) &&
86628679Sbrian		     ((VarDialTries && tries >= VarDialTries) ||
86728679Sbrian		      res == EX_SIG)) {
86824843Sbrian	    /* I give up !  Can't get through :( */
86924939Sbrian	    StartRedialTimer(VarRedialTimeout);
87030715Sbrian	    dial_up = 0;
87128679Sbrian	    reconnectState = RECON_UNKNOWN;
87228679Sbrian	    reconnectCount = 0;
87324843Sbrian	    tries = 0;
87424843Sbrian	  } else if (VarNextPhone == NULL)
87524843Sbrian	    /* Dial failed. Keep quite during redial wait period. */
87624939Sbrian	    StartRedialTimer(VarRedialTimeout);
87724843Sbrian	  else
87824939Sbrian	    StartRedialTimer(VarRedialNextTimeout);
87911336Samurai	}
88011336Samurai      }
8817001Samurai    }
8829448Samurai    qlen = ModemQlen();
88313733Sdfr
88413733Sdfr    if (qlen == 0) {
88513733Sdfr      IpStartOutput();
88613733Sdfr      qlen = ModemQlen();
88713733Sdfr    }
88823598Sache    if (modem >= 0) {
88923598Sache      if (modem + 1 > nfds)
89023598Sache	nfds = modem + 1;
8917001Samurai      FD_SET(modem, &rfds);
8927001Samurai      FD_SET(modem, &efds);
8939448Samurai      if (qlen > 0) {
8947001Samurai	FD_SET(modem, &wfds);
8957001Samurai      }
8967001Samurai    }
89723598Sache    if (server >= 0) {
89823598Sache      if (server + 1 > nfds)
89923598Sache	nfds = server + 1;
90023598Sache      FD_SET(server, &rfds);
90123598Sache    }
9026059Samurai
90332063Sbrian#ifndef SIGALRM
90428679Sbrian    /*
90528679Sbrian     * *** IMPORTANT ***
90628679Sbrian     * CPU is serviced every TICKUNIT micro seconds. This value must be chosen
90732063Sbrian     * with great care. If this values is too big, it results in loss of
90832063Sbrian     * characters from the modem and poor response.  If this value is too
90932063Sbrian     * small, ppp eats too much CPU time.
9106059Samurai     */
91132063Sbrian    usleep(TICKUNIT);
9126059Samurai    TimerService();
91323840Sbrian#else
91423840Sbrian    handle_signals();
9156735Samurai#endif
91610877Sbde
91710877Sbde    /* If there are aren't many packets queued, look for some more. */
91823598Sache    if (qlen < 20 && tun_in >= 0) {
91923598Sache      if (tun_in + 1 > nfds)
92023598Sache	nfds = tun_in + 1;
92110877Sbde      FD_SET(tun_in, &rfds);
92223598Sache    }
92323598Sache    if (netfd >= 0) {
92423598Sache      if (netfd + 1 > nfds)
92523598Sache	nfds = netfd + 1;
9266059Samurai      FD_SET(netfd, &rfds);
9276059Samurai      FD_SET(netfd, &efds);
9286059Samurai    }
92928679Sbrian#ifndef SIGALRM
9307001Samurai
9316059Samurai    /*
93228679Sbrian     * Normally, select() will not block because modem is writable. In AUTO
93328679Sbrian     * mode, select will block until we find packet from tun
9346059Samurai     */
93528679Sbrian    tp = (RedialTimer.state == TIMER_RUNNING) ? &timeout : NULL;
93623598Sache    i = select(nfds, &rfds, &wfds, &efds, tp);
9376735Samurai#else
93828679Sbrian
9398857Srgrimes    /*
94028679Sbrian     * When SIGALRM timer is running, a select function will be return -1 and
94128679Sbrian     * EINTR after a Time Service signal hundler is done.  If the redial
94228679Sbrian     * timer is not running and we are trying to dial, poll with a 0 value
94328679Sbrian     * timer.
9447001Samurai     */
94511336Samurai    tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL;
94623598Sache    i = select(nfds, &rfds, &wfds, &efds, tp);
9476735Samurai#endif
94822074Sbrian
94928679Sbrian    if (i == 0) {
95028679Sbrian      continue;
9516059Samurai    }
95228679Sbrian    if (i < 0) {
95328679Sbrian      if (errno == EINTR) {
95428679Sbrian	handle_signals();
95528679Sbrian	continue;
95628679Sbrian      }
95728974Sbrian      LogPrintf(LogERROR, "DoLoop: select(): %s\n", strerror(errno));
95828679Sbrian      break;
9598857Srgrimes    }
96023598Sache    if ((netfd >= 0 && FD_ISSET(netfd, &efds)) || (modem >= 0 && FD_ISSET(modem, &efds))) {
96126516Sbrian      LogPrintf(LogALERT, "Exception detected.\n");
9626059Samurai      break;
9636059Samurai    }
96423598Sache    if (server >= 0 && FD_ISSET(server, &rfds)) {
96531825Sbrian      wfd = accept(server, sa, &ssize);
96624753Sache      if (wfd < 0) {
96728974Sbrian	LogPrintf(LogERROR, "DoLoop: accept(): %s\n", strerror(errno));
96824753Sache	continue;
96924753Sache      }
97031825Sbrian      switch (sa->sa_family) {
97131825Sbrian        case AF_LOCAL:
97231825Sbrian          LogPrintf(LogPHASE, "Connected to local client.\n");
97331825Sbrian          break;
97431825Sbrian        case AF_INET:
97531931Sbrian          if (ntohs(sin->sin_port) < 1024) {
97631825Sbrian            LogPrintf(LogALERT, "Rejected client connection from %s:%u"
97731825Sbrian                      "(invalid port number) !\n",
97831931Sbrian                      inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
97931825Sbrian	    close(wfd);
98031825Sbrian	    continue;
98131825Sbrian          }
98231825Sbrian          LogPrintf(LogPHASE, "Connected to client from %s:%u\n",
98331825Sbrian                    inet_ntoa(sin->sin_addr), sin->sin_port);
98431825Sbrian          break;
98531825Sbrian        default:
98631825Sbrian	  write(wfd, "Unrecognised access !\n", 22);
98731825Sbrian	  close(wfd);
98831825Sbrian	  continue;
98931825Sbrian      }
99023598Sache      if (netfd >= 0) {
99131825Sbrian	write(wfd, "Connection already in use.\n", 27);
9926059Samurai	close(wfd);
9936059Samurai	continue;
99431825Sbrian      }
99531825Sbrian      netfd = wfd;
99626516Sbrian      VarTerm = fdopen(netfd, "a+");
99731081Sbrian      LocalAuthInit();
99830913Sbrian      IsInteractive(1);
99925630Sbrian      Prompt();
10006059Samurai    }
100131514Sbrian    if (netfd >= 0 && FD_ISSET(netfd, &rfds))
10026059Samurai      /* something to read from tty */
10036059Samurai      ReadTty();
100431514Sbrian    if (modem >= 0 && FD_ISSET(modem, &wfds)) {
100531514Sbrian      /* ready to write into modem */
100631514Sbrian      ModemStartOutput(modem);
100731514Sbrian      if (modem < 0)
100831514Sbrian        dial_up = 1;
10096059Samurai    }
101031514Sbrian    if (modem >= 0 && FD_ISSET(modem, &rfds)) {
101131514Sbrian      /* something to read from modem */
101231514Sbrian      if (LcpFsm.state <= ST_CLOSED)
101331514Sbrian	nointr_usleep(10000);
101431962Sbrian      n = read(modem, rbuff, sizeof rbuff);
101531514Sbrian      if ((mode & MODE_DIRECT) && n <= 0) {
101631514Sbrian	DownConnection();
101731514Sbrian      } else
101831514Sbrian	LogDumpBuff(LogASYNC, "ReadFromModem", rbuff, n);
10196059Samurai
102031514Sbrian      if (LcpFsm.state <= ST_CLOSED) {
102131514Sbrian	/*
102231514Sbrian	 * In dedicated mode, we just discard input until LCP is started.
102331514Sbrian	 */
102431514Sbrian	if (!(mode & MODE_DEDICATED)) {
102531514Sbrian	  cp = HdlcDetect(rbuff, n);
102631514Sbrian	  if (cp) {
102731514Sbrian	    /*
102831514Sbrian	     * LCP packet is detected. Turn ourselves into packet mode.
102931514Sbrian	     */
103031514Sbrian	    if (cp != rbuff) {
103131514Sbrian	      write(modem, rbuff, cp - rbuff);
103231514Sbrian	      write(modem, "\r\n", 2);
103331514Sbrian	    }
103432658Sbrian	    PacketMode(0);
103531514Sbrian	  } else
103631514Sbrian	    write(fileno(VarTerm), rbuff, n);
10376059Samurai	}
103831514Sbrian      } else {
103931514Sbrian	if (n > 0)
104031514Sbrian	  AsyncInput(rbuff, n);
10416059Samurai      }
10426059Samurai    }
104328679Sbrian    if (tun_in >= 0 && FD_ISSET(tun_in, &rfds)) {	/* something to read
104428679Sbrian							 * from tun */
104531962Sbrian      n = read(tun_in, &tun, sizeof tun);
10466059Samurai      if (n < 0) {
104728974Sbrian	LogPrintf(LogERROR, "read from tun: %s\n", strerror(errno));
10486059Samurai	continue;
10496059Samurai      }
105031962Sbrian      n -= sizeof tun - sizeof tun.data;
105131195Sbrian      if (n <= 0) {
105231195Sbrian	LogPrintf(LogERROR, "read from tun: Only %d bytes read\n", n);
105331195Sbrian	continue;
105431195Sbrian      }
105531195Sbrian      if (!tun_check_header(tun, AF_INET))
105631195Sbrian          continue;
105728679Sbrian      if (((struct ip *) rbuff)->ip_dst.s_addr == IpcpInfo.want_ipaddr.s_addr) {
105828536Sbrian	/* we've been asked to send something addressed *to* us :( */
105928536Sbrian	if (VarLoopback) {
106028536Sbrian	  pri = PacketCheck(rbuff, n, FL_IN);
106128536Sbrian	  if (pri >= 0) {
106228536Sbrian	    struct mbuf *bp;
106328679Sbrian
106431343Sbrian#ifndef NOALIAS
106528536Sbrian	    if (mode & MODE_ALIAS) {
106628536Sbrian	      VarPacketAliasIn(rbuff, sizeof rbuff);
106728679Sbrian	      n = ntohs(((struct ip *) rbuff)->ip_len);
106828536Sbrian	    }
106931343Sbrian#endif
107028536Sbrian	    bp = mballoc(n, MB_IPIN);
107130715Sbrian	    memcpy(MBUF_CTOP(bp), rbuff, n);
107228536Sbrian	    IpInput(bp);
107328536Sbrian	    LogPrintf(LogDEBUG, "Looped back packet addressed to myself\n");
107428536Sbrian	  }
107528536Sbrian	  continue;
107628679Sbrian	} else
107728536Sbrian	  LogPrintf(LogDEBUG, "Oops - forwarding packet addressed to myself\n");
107828536Sbrian      }
107928536Sbrian
10806059Samurai      /*
108128679Sbrian       * Process on-demand dialup. Output packets are queued within tunnel
108228679Sbrian       * device until IPCP is opened.
10836059Samurai       */
108432039Sbrian      if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO) &&
108532039Sbrian	  (pri = PacketCheck(rbuff, n, FL_DIAL)) >= 0)
108632039Sbrian        dial_up = 1;
108732039Sbrian
10887001Samurai      pri = PacketCheck(rbuff, n, FL_OUT);
108920365Sjkh      if (pri >= 0) {
109031343Sbrian#ifndef NOALIAS
109128679Sbrian	if (mode & MODE_ALIAS) {
109228679Sbrian	  VarPacketAliasOut(rbuff, sizeof rbuff);
109328679Sbrian	  n = ntohs(((struct ip *) rbuff)->ip_len);
109428679Sbrian	}
109531343Sbrian#endif
10966059Samurai	IpEnqueue(pri, rbuff, n);
109720365Sjkh      }
10986059Samurai    }
10996059Samurai  }
110026516Sbrian  LogPrintf(LogDEBUG, "Job (DoLoop) done.\n");
11016059Samurai}
1102