main.c revision 31582
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 *
2031514Sbrian * $Id: main.c,v 1.105 1997/11/22 03:37:39 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>
3030715Sbrian#include <netinet/in.h>
3130715Sbrian#include <netinet/in_systm.h>
3230715Sbrian#include <netinet/ip.h>
3330715Sbrian#include <arpa/inet.h>
3430715Sbrian#include <netdb.h>
3531195Sbrian#include <net/if.h>
3631343Sbrian#ifdef __FreeBSD__
3731195Sbrian#include <net/if_var.h>
3831343Sbrian#endif
3931195Sbrian#include <net/if_tun.h>
4030715Sbrian
4130715Sbrian#include <errno.h>
426059Samurai#include <fcntl.h>
4311336Samurai#include <paths.h>
4430715Sbrian#include <signal.h>
4530715Sbrian#include <stdio.h>
4630715Sbrian#include <stdlib.h>
4730715Sbrian#include <string.h>
486059Samurai#include <sys/time.h>
4930715Sbrian#include <sys/wait.h>
5030715Sbrian#include <sysexits.h>
516059Samurai#include <termios.h>
5218786Sjkh#include <unistd.h>
5330715Sbrian
5431343Sbrian#include "command.h"
5530715Sbrian#include "mbuf.h"
5630715Sbrian#include "log.h"
5730715Sbrian#include "defs.h"
5831061Sbrian#include "id.h"
5930715Sbrian#include "timer.h"
6030715Sbrian#include "fsm.h"
616059Samurai#include "modem.h"
626059Samurai#include "os.h"
636059Samurai#include "hdlc.h"
6431514Sbrian#include "lcp.h"
6513389Sphk#include "ccp.h"
666059Samurai#include "ipcp.h"
6726142Sbrian#include "loadalias.h"
686059Samurai#include "vars.h"
696735Samurai#include "auth.h"
707001Samurai#include "filter.h"
7113389Sphk#include "systems.h"
7213389Sphk#include "ip.h"
7323840Sbrian#include "sig.h"
7426940Sbrian#include "server.h"
7528536Sbrian#include "lcpproto.h"
7630715Sbrian#include "main.h"
7730715Sbrian#include "vjcomp.h"
7830715Sbrian#include "async.h"
7931158Sbrian#include "pathnames.h"
8031195Sbrian#include "tun.h"
8131343Sbrian#include "route.h"
826059Samurai
836735Samurai#ifndef O_NONBLOCK
846735Samurai#ifdef O_NDELAY
856735Samurai#define	O_NONBLOCK O_NDELAY
866735Samurai#endif
876735Samurai#endif
886735Samurai
8930715Sbrianint TermMode = 0;
9030715Sbrianint tunno = 0;
916059Samurai
9228679Sbrianstatic struct termios oldtio;	/* Original tty mode */
9328679Sbrianstatic struct termios comtio;	/* Command level tty mode */
9420813Sjkhstatic pid_t BGPid = 0;
9525634Sbrianstatic char pid_filename[MAXPATHLEN];
9627061Sbrianstatic int dial_up;
976059Samurai
9830715Sbrianstatic void DoLoop(void);
9930715Sbrianstatic void TerminalStop(int);
10031343Sbrianstatic const char *ex_desc(int);
10130715Sbrian
1026059Samuraistatic void
10326858SbrianTtyInit(int DontWantInt)
1046059Samurai{
1056059Samurai  struct termios newtio;
1066059Samurai  int stat;
1076059Samurai
1086059Samurai  stat = fcntl(0, F_GETFL, 0);
10925630Sbrian  if (stat > 0) {
11028679Sbrian    stat |= O_NONBLOCK;
11128679Sbrian    (void) fcntl(0, F_SETFL, stat);
11225630Sbrian  }
1136059Samurai  newtio = oldtio;
11428679Sbrian  newtio.c_lflag &= ~(ECHO | ISIG | ICANON);
1156059Samurai  newtio.c_iflag = 0;
1166059Samurai  newtio.c_oflag &= ~OPOST;
1176059Samurai  newtio.c_cc[VEOF] = _POSIX_VDISABLE;
11826858Sbrian  if (DontWantInt)
11926858Sbrian    newtio.c_cc[VINTR] = _POSIX_VDISABLE;
1206059Samurai  newtio.c_cc[VMIN] = 1;
1216059Samurai  newtio.c_cc[VTIME] = 0;
1226059Samurai  newtio.c_cflag |= CS8;
1236735Samurai  tcsetattr(0, TCSADRAIN, &newtio);
1246059Samurai  comtio = newtio;
1256059Samurai}
1266059Samurai
1276059Samurai/*
1286059Samurai *  Set tty into command mode. We allow canonical input and echo processing.
1296059Samurai */
13010528Samuraivoid
13128679SbrianTtyCommandMode(int prompt)
1326059Samurai{
1336059Samurai  struct termios newtio;
1346059Samurai  int stat;
1356059Samurai
1366059Samurai  if (!(mode & MODE_INTER))
1376059Samurai    return;
1386735Samurai  tcgetattr(0, &newtio);
13928679Sbrian  newtio.c_lflag |= (ECHO | ISIG | ICANON);
1406059Samurai  newtio.c_iflag = oldtio.c_iflag;
1416059Samurai  newtio.c_oflag |= OPOST;
1426735Samurai  tcsetattr(0, TCSADRAIN, &newtio);
1436059Samurai  stat = fcntl(0, F_GETFL, 0);
14425630Sbrian  if (stat > 0) {
14528679Sbrian    stat |= O_NONBLOCK;
14628679Sbrian    (void) fcntl(0, F_SETFL, stat);
14725630Sbrian  }
1486059Samurai  TermMode = 0;
14928679Sbrian  if (prompt)
15028679Sbrian    Prompt();
1516059Samurai}
1526059Samurai
1536059Samurai/*
1546059Samurai * Set tty into terminal mode which is used while we invoke term command.
1556059Samurai */
1566059Samuraivoid
1576059SamuraiTtyTermMode()
1586059Samurai{
1596059Samurai  int stat;
1606059Samurai
1616735Samurai  tcsetattr(0, TCSADRAIN, &comtio);
1626059Samurai  stat = fcntl(0, F_GETFL, 0);
16325630Sbrian  if (stat > 0) {
16428679Sbrian    stat &= ~O_NONBLOCK;
16528679Sbrian    (void) fcntl(0, F_SETFL, stat);
16625630Sbrian  }
1676059Samurai  TermMode = 1;
1686059Samurai}
1696059Samurai
1706059Samuraivoid
17110528SamuraiTtyOldMode()
1726059Samurai{
1736059Samurai  int stat;
1746059Samurai
1756059Samurai  stat = fcntl(0, F_GETFL, 0);
17625630Sbrian  if (stat > 0) {
17728679Sbrian    stat &= ~O_NONBLOCK;
17828679Sbrian    (void) fcntl(0, F_SETFL, stat);
17925630Sbrian  }
1806735Samurai  tcsetattr(0, TCSANOW, &oldtio);
18110528Samurai}
18210528Samurai
18310528Samuraivoid
18428679SbrianCleanup(int excode)
18510528Samurai{
18631203Sbrian  DropClient();
18731081Sbrian  ServerClose();
18830825Sbrian  OsInterfaceDown(1);
18930825Sbrian  HangupModem(1);
19030697Sbrian  nointr_sleep(1);
19131121Sbrian  DeleteIfRoutes(1);
19231061Sbrian  ID0unlink(pid_filename);
19323863Sbrian  if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) {
19423863Sbrian    char c = EX_ERRDEAD;
19528679Sbrian
19628679Sbrian    if (write(BGFiledes[1], &c, 1) == 1)
19728679Sbrian      LogPrintf(LogPHASE, "Parent notified of failure.\n");
19823863Sbrian    else
19928679Sbrian      LogPrintf(LogPHASE, "Failed to notify parent of failure.\n");
20023863Sbrian    close(BGFiledes[1]);
20123863Sbrian  }
20228679Sbrian  LogPrintf(LogPHASE, "PPP Terminated (%s).\n", ex_desc(excode));
20310528Samurai  TtyOldMode();
20431061Sbrian  LogClose();
2056059Samurai
2066059Samurai  exit(excode);
2076059Samurai}
2086059Samurai
2096059Samuraistatic void
21028679SbrianCloseConnection(int signo)
2116059Samurai{
21226858Sbrian  /* NOTE, these are manual, we've done a setsid() */
21331121Sbrian  pending_signal(SIGINT, SIG_IGN);
21427157Sbrian  LogPrintf(LogPHASE, "Caught signal %d, abort connection\n", signo);
21528679Sbrian  reconnectState = RECON_FALSE;
21628684Sbrian  reconnectCount = 0;
21728684Sbrian  DownConnection();
21830715Sbrian  dial_up = 0;
21931121Sbrian  pending_signal(SIGINT, CloseConnection);
2206059Samurai}
2216059Samurai
2226059Samuraistatic void
22328679SbrianCloseSession(int signo)
2246059Samurai{
22528679Sbrian  if (BGPid) {
22628679Sbrian    kill(BGPid, SIGINT);
22728679Sbrian    exit(EX_TERM);
22828679Sbrian  }
22928679Sbrian  LogPrintf(LogPHASE, "Signal %d, terminate.\n", signo);
23028679Sbrian  reconnect(RECON_FALSE);
23128679Sbrian  LcpClose();
23228679Sbrian  Cleanup(EX_TERM);
2336059Samurai}
2346059Samurai
23510528Samuraistatic void
23631343SbrianTerminalCont(int signo)
23710528Samurai{
23823840Sbrian  pending_signal(SIGCONT, SIG_DFL);
23923840Sbrian  pending_signal(SIGTSTP, TerminalStop);
24010528Samurai  TtyCommandMode(getpgrp() == tcgetpgrp(0));
24110528Samurai}
24210528Samurai
24310528Samuraistatic void
24428679SbrianTerminalStop(int signo)
24510528Samurai{
24623840Sbrian  pending_signal(SIGCONT, TerminalCont);
24710528Samurai  TtyOldMode();
24823840Sbrian  pending_signal(SIGTSTP, SIG_DFL);
24910528Samurai  kill(getpid(), signo);
25010528Samurai}
25110528Samurai
25226940Sbrianstatic void
25328679SbrianSetUpServer(int signo)
25426940Sbrian{
25526940Sbrian  int res;
25628679Sbrian
25731081Sbrian  VarHaveLocalAuthKey = 0;
25831081Sbrian  LocalAuthInit();
25928679Sbrian  if ((res = ServerTcpOpen(SERVER_PORT + tunno)) != 0)
26029083Sbrian    LogPrintf(LogERROR, "SIGUSR1: Failed %d to open port %d\n",
26129083Sbrian	      res, SERVER_PORT + tunno);
26226940Sbrian}
26326940Sbrian
26431081Sbrianstatic void
26531081SbrianBringDownServer(int signo)
26631081Sbrian{
26731081Sbrian  VarHaveLocalAuthKey = 0;
26831081Sbrian  LocalAuthInit();
26931081Sbrian  ServerClose();
27031081Sbrian}
27131081Sbrian
27231343Sbrianstatic const char *
27325908Sbrianex_desc(int ex)
27425908Sbrian{
27525908Sbrian  static char num[12];
27631343Sbrian  static const char *desc[] = {
27731343Sbrian    "normal", "start", "sock", "modem", "dial", "dead", "done",
27831343Sbrian    "reboot", "errdead", "hangup", "term", "nodial", "nologin"
27931343Sbrian  };
28010528Samurai
28128679Sbrian  if (ex >= 0 && ex < sizeof(desc) / sizeof(*desc))
28225908Sbrian    return desc[ex];
28325908Sbrian  snprintf(num, sizeof num, "%d", ex);
28425908Sbrian  return num;
28525908Sbrian}
28625908Sbrian
28730715Sbrianstatic void
28831343SbrianUsage(void)
2896059Samurai{
29020120Snate  fprintf(stderr,
29131343Sbrian	  "Usage: ppp [-auto | -background | -direct | -dedicated | -ddial ]"
29231343Sbrian#ifndef NOALIAS
29331343Sbrian          " [ -alias ]"
29431343Sbrian#endif
29531343Sbrian          " [system]\n");
2966059Samurai  exit(EX_START);
2976059Samurai}
2986059Samurai
29931197Sbrianstatic char *
3006059SamuraiProcessArgs(int argc, char **argv)
3016059Samurai{
3026059Samurai  int optc;
3036059Samurai  char *cp;
3046059Samurai
3056059Samurai  optc = 0;
30631121Sbrian  mode = MODE_INTER;
3076059Samurai  while (argc > 0 && **argv == '-') {
3086059Samurai    cp = *argv + 1;
30931121Sbrian    if (strcmp(cp, "auto") == 0) {
3106059Samurai      mode |= MODE_AUTO;
31131121Sbrian      mode &= ~MODE_INTER;
31231121Sbrian    } else if (strcmp(cp, "background") == 0) {
31331121Sbrian      mode |= MODE_BACKGROUND;
31431121Sbrian      mode &= ~MODE_INTER;
31531121Sbrian    } else if (strcmp(cp, "direct") == 0) {
3166059Samurai      mode |= MODE_DIRECT;
31731121Sbrian      mode &= ~MODE_INTER;
31831121Sbrian    } else if (strcmp(cp, "dedicated") == 0) {
3196059Samurai      mode |= MODE_DEDICATED;
32031121Sbrian      mode &= ~MODE_INTER;
32131121Sbrian    } else if (strcmp(cp, "ddial") == 0) {
32231121Sbrian      mode |= MODE_DDIAL;
32331121Sbrian      mode &= ~MODE_INTER;
32431343Sbrian#ifndef NOALIAS
32531121Sbrian    } else if (strcmp(cp, "alias") == 0) {
32626142Sbrian      if (loadAliasHandlers(&VarAliasHandlers) == 0)
32728679Sbrian	mode |= MODE_ALIAS;
32826142Sbrian      else
32928679Sbrian	LogPrintf(LogWARN, "Cannot load alias library\n");
33028679Sbrian      optc--;			/* this option isn't exclusive */
33131343Sbrian#endif
33228679Sbrian    } else
3336059Samurai      Usage();
3346059Samurai    optc++;
33528679Sbrian    argv++;
33628679Sbrian    argc--;
3376059Samurai  }
3386059Samurai  if (argc > 1) {
3396059Samurai    fprintf(stderr, "specify only one system label.\n");
3406059Samurai    exit(EX_START);
3416059Samurai  }
3426059Samurai
3436059Samurai  if (optc > 1) {
3446059Samurai    fprintf(stderr, "specify only one mode.\n");
3456059Samurai    exit(EX_START);
3466059Samurai  }
34731197Sbrian
34831197Sbrian  return argc == 1 ? *argv : NULL;	/* Don't SetLabel yet ! */
3496059Samurai}
3506059Samurai
3516059Samuraistatic void
35231343SbrianGreetings(void)
3536059Samurai{
35426516Sbrian  if (VarTerm) {
35526516Sbrian    fprintf(VarTerm, "User Process PPP. Written by Toshiharu OHNO.\n");
35626516Sbrian    fflush(VarTerm);
35726516Sbrian  }
3586059Samurai}
3596059Samurai
36026940Sbrianint
36128679Sbrianmain(int argc, char **argv)
3626059Samurai{
36325707Sbrian  FILE *lockfile;
36431197Sbrian  char *name, *label;
36526516Sbrian
36626551Sbrian  VarTerm = 0;
36730715Sbrian  name = strrchr(argv[0], '/');
36828679Sbrian  LogOpen(name ? name + 1 : argv[0]);
36926516Sbrian
37028679Sbrian  argc--;
37128679Sbrian  argv++;
37231197Sbrian  label = ProcessArgs(argc, argv);
37331121Sbrian  if (!(mode & MODE_DIRECT))
37426551Sbrian    VarTerm = stdout;
37531121Sbrian
37631121Sbrian  ID0init();
37731158Sbrian  if (ID0realuid() != 0) {
37831158Sbrian    char conf[200], *ptr;
37931158Sbrian
38031158Sbrian    snprintf(conf, sizeof conf, "%s/%s", _PATH_PPP, CONFFILE);
38131158Sbrian    do {
38231158Sbrian      if (!access(conf, W_OK)) {
38331158Sbrian        LogPrintf(LogALERT, "ppp: Access violation: Please protect %s\n", conf);
38431158Sbrian        return -1;
38531158Sbrian      }
38631158Sbrian      ptr = conf + strlen(conf)-2;
38731158Sbrian      while (ptr > conf && *ptr != '/')
38831158Sbrian        *ptr-- = '\0';
38931158Sbrian    } while (ptr >= conf);
39031158Sbrian  }
39131158Sbrian
39231197Sbrian  if (!ValidSystem(label)) {
39331121Sbrian    fprintf(stderr, "You may not use ppp in this mode with this label\n");
39431157Sbrian    if (mode & MODE_DIRECT) {
39531157Sbrian      const char *l;
39631197Sbrian      l = label ? label : "default";
39731157Sbrian      VarTerm = 0;
39831157Sbrian      LogPrintf(LogWARN, "Label %s rejected -direct connection\n", l);
39931157Sbrian    }
40031157Sbrian    LogClose();
40131121Sbrian    return 1;
40229083Sbrian  }
40331121Sbrian
40431196Sbrian  if (!GetShortHost())
40531196Sbrian    return 1;
40626551Sbrian  Greetings();
4076059Samurai  IpcpDefAddress();
4086059Samurai
40931285Sbrian  if (mode & MODE_INTER)
41031285Sbrian    VarLocalAuth = LOCAL_AUTH;
41131285Sbrian
41226516Sbrian  if (SelectSystem("default", CONFFILE) < 0 && VarTerm)
41326516Sbrian    fprintf(VarTerm, "Warning: No default entry is given in config file.\n");
4146059Samurai
4156059Samurai  if (OpenTunnel(&tunno) < 0) {
41626940Sbrian    LogPrintf(LogWARN, "open_tun: %s\n", strerror(errno));
41726940Sbrian    return EX_START;
4186059Samurai  }
4196059Samurai  if (mode & MODE_INTER) {
42026516Sbrian    fprintf(VarTerm, "Interactive mode\n");
42126690Sbrian    netfd = STDOUT_FILENO;
42231121Sbrian  } else if ((mode & MODE_OUTGOING_DAEMON) && !(mode & MODE_DEDICATED))
42331197Sbrian    if (label == NULL) {
42426516Sbrian      if (VarTerm)
42528679Sbrian	fprintf(VarTerm, "Destination system must be specified in"
42628679Sbrian		" auto, background or ddial mode.\n");
42726940Sbrian      return EX_START;
4286059Samurai    }
42931121Sbrian
43028679Sbrian  tcgetattr(0, &oldtio);	/* Save original tty mode */
4316059Samurai
43227157Sbrian  pending_signal(SIGHUP, CloseSession);
43323840Sbrian  pending_signal(SIGTERM, CloseSession);
43427157Sbrian  pending_signal(SIGINT, CloseConnection);
43523840Sbrian  pending_signal(SIGQUIT, CloseSession);
4366735Samurai#ifdef SIGPIPE
43724753Sache  signal(SIGPIPE, SIG_IGN);
4386735Samurai#endif
4396735Samurai#ifdef SIGALRM
44023840Sbrian  pending_signal(SIGALRM, SIG_IGN);
4416735Samurai#endif
44228679Sbrian  if (mode & MODE_INTER) {
44310528Samurai#ifdef SIGTSTP
44426940Sbrian    pending_signal(SIGTSTP, TerminalStop);
44510528Samurai#endif
44610528Samurai#ifdef SIGTTIN
44726940Sbrian    pending_signal(SIGTTIN, TerminalStop);
44810528Samurai#endif
44910528Samurai#ifdef SIGTTOU
45026940Sbrian    pending_signal(SIGTTOU, SIG_IGN);
45110528Samurai#endif
45226940Sbrian  }
45331121Sbrian  if (!(mode & MODE_INTER)) {
45426940Sbrian#ifdef SIGUSR1
45526940Sbrian    pending_signal(SIGUSR1, SetUpServer);
45626940Sbrian#endif
45731081Sbrian#ifdef SIGUSR2
45831081Sbrian    pending_signal(SIGUSR2, BringDownServer);
45931081Sbrian#endif
46031121Sbrian  }
4616059Samurai
46231197Sbrian  if (label) {
46331197Sbrian    if (SelectSystem(label, CONFFILE) < 0) {
46431154Sbrian      LogPrintf(LogWARN, "Destination system %s not found in conf file.\n",
46531154Sbrian                GetLabel());
4666059Samurai      Cleanup(EX_START);
4676059Samurai    }
46831197Sbrian    /*
46931197Sbrian     * We don't SetLabel() 'till now in case SelectSystem() has an
47031197Sbrian     * embeded load "otherlabel" command.
47131197Sbrian     */
47231197Sbrian    SetLabel(label);
47331121Sbrian    if (mode & MODE_OUTGOING_DAEMON &&
47431121Sbrian	DefHisAddress.ipaddr.s_addr == INADDR_ANY) {
47531154Sbrian      LogPrintf(LogWARN, "You must \"set ifaddr\" in label %s for"
47631197Sbrian		" auto, background or ddial mode.\n", label);
4776059Samurai      Cleanup(EX_START);
4786059Samurai    }
4796059Samurai  }
48026940Sbrian
48131121Sbrian  if (mode & MODE_DAEMON) {
48220813Sjkh    if (mode & MODE_BACKGROUND) {
48328679Sbrian      if (pipe(BGFiledes)) {
48428974Sbrian	LogPrintf(LogERROR, "pipe: %s\n", strerror(errno));
48520813Sjkh	Cleanup(EX_SOCK);
48620813Sjkh      }
4876059Samurai    }
4886059Samurai
4896059Samurai    if (!(mode & MODE_DIRECT)) {
49020813Sjkh      pid_t bgpid;
49111336Samurai
49228679Sbrian      bgpid = fork();
49320813Sjkh      if (bgpid == -1) {
49428974Sbrian	LogPrintf(LogERROR, "fork: %s\n", strerror(errno));
49528679Sbrian	Cleanup(EX_SOCK);
49620813Sjkh      }
49720813Sjkh      if (bgpid) {
49820813Sjkh	char c = EX_NORMAL;
49911336Samurai
50020813Sjkh	if (mode & MODE_BACKGROUND) {
50120813Sjkh	  /* Wait for our child to close its pipe before we exit. */
50220813Sjkh	  BGPid = bgpid;
50328679Sbrian	  close(BGFiledes[1]);
50425908Sbrian	  if (read(BGFiledes[0], &c, 1) != 1) {
50526516Sbrian	    fprintf(VarTerm, "Child exit, no status.\n");
50628679Sbrian	    LogPrintf(LogPHASE, "Parent: Child exit, no status.\n");
50725908Sbrian	  } else if (c == EX_NORMAL) {
50826516Sbrian	    fprintf(VarTerm, "PPP enabled.\n");
50928679Sbrian	    LogPrintf(LogPHASE, "Parent: PPP enabled.\n");
51025908Sbrian	  } else {
51128679Sbrian	    fprintf(VarTerm, "Child failed (%s).\n", ex_desc((int) c));
51226516Sbrian	    LogPrintf(LogPHASE, "Parent: Child failed (%s).\n",
51328679Sbrian		      ex_desc((int) c));
51428679Sbrian	  }
51528679Sbrian	  close(BGFiledes[0]);
51620813Sjkh	}
51728679Sbrian	return c;
51823863Sbrian      } else if (mode & MODE_BACKGROUND)
51928679Sbrian	close(BGFiledes[0]);
52025707Sbrian    }
52120813Sjkh
52228679Sbrian    VarTerm = 0;		/* We know it's currently stdout */
52329551Sbrian    close(1);
52426686Sbrian    close(2);
52526551Sbrian
52626686Sbrian    if (mode & MODE_DIRECT)
52726858Sbrian      TtyInit(1);
52831121Sbrian    else if (mode & MODE_DAEMON) {
52926686Sbrian      setsid();
53029551Sbrian      close(0);
53126686Sbrian    }
5326059Samurai  } else {
53326858Sbrian    TtyInit(0);
53410528Samurai    TtyCommandMode(1);
5356059Samurai  }
53629696Sbrian
53729696Sbrian  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);
54329696Sbrian  } else
54429696Sbrian    LogPrintf(LogALERT, "Warning: Can't create %s: %s\n",
54529696Sbrian              pid_filename, strerror(errno));
54629696Sbrian
54726516Sbrian  LogPrintf(LogPHASE, "PPP Started.\n");
5486059Samurai
5496059Samurai
5506059Samurai  do
55128679Sbrian    DoLoop();
5526059Samurai  while (mode & MODE_DEDICATED);
5536059Samurai
5546059Samurai  Cleanup(EX_DONE);
55526940Sbrian  return 0;
5566059Samurai}
5576059Samurai
5586059Samurai/*
55920813Sjkh *  Turn into packet mode, where we speak PPP.
5606059Samurai */
5616059Samuraivoid
5626059SamuraiPacketMode()
5636059Samurai{
56431034Sbrian  if (RawModem() < 0) {
56526516Sbrian    LogPrintf(LogWARN, "PacketMode: Not connected.\n");
5666059Samurai    return;
5676059Samurai  }
5686059Samurai  AsyncInit();
56930187Sbrian  VjInit(15);
5706059Samurai  LcpInit();
5716059Samurai  IpcpInit();
5726059Samurai  CcpInit();
5736059Samurai  LcpUp();
5746059Samurai
57525872Sbrian  LcpOpen(VarOpenMode);
57631121Sbrian  if (mode & MODE_INTER)
57710528Samurai    TtyCommandMode(1);
57831121Sbrian  if (VarTerm) {
57931121Sbrian    fprintf(VarTerm, "Packet mode.\n");
58031121Sbrian    aft_cmd = 1;
5816059Samurai  }
5826059Samurai}
5836059Samurai
5846059Samuraistatic void
58531343SbrianShowHelp(void)
5866059Samurai{
58726901Sbrian  fprintf(stderr, "The following commands are available:\r\n");
58826901Sbrian  fprintf(stderr, " ~p\tEnter Packet mode\r\n");
58926901Sbrian  fprintf(stderr, " ~-\tDecrease log level\r\n");
59026901Sbrian  fprintf(stderr, " ~+\tIncrease log level\r\n");
59126901Sbrian  fprintf(stderr, " ~t\tShow timers (only in \"log debug\" mode)\r\n");
59226901Sbrian  fprintf(stderr, " ~m\tShow memory map (only in \"log debug\" mode)\r\n");
59326901Sbrian  fprintf(stderr, " ~.\tTerminate program\r\n");
59426901Sbrian  fprintf(stderr, " ~?\tThis help\r\n");
5956059Samurai}
5966059Samurai
5976059Samuraistatic void
59831343SbrianReadTty(void)
5996059Samurai{
6006059Samurai  int n;
6016059Samurai  char ch;
6026059Samurai  static int ttystate;
60331070Sbrian  char linebuff[LINE_LEN];
60428679Sbrian
60526516Sbrian  LogPrintf(LogDEBUG, "termode = %d, netfd = %d, mode = %d\n",
60628679Sbrian	    TermMode, netfd, mode);
6076059Samurai  if (!TermMode) {
60828679Sbrian    n = read(netfd, linebuff, sizeof(linebuff) - 1);
6096735Samurai    if (n > 0) {
61026516Sbrian      aft_cmd = 1;
61130913Sbrian      if (linebuff[n-1] == '\n')
61230913Sbrian        linebuff[--n] = '\0';
61331156Sbrian      if (n)
61431156Sbrian        DecodeCommand(linebuff, n, IsInteractive(0) ? NULL : "Client");
61531156Sbrian      Prompt();
61631240Sbrian    } else if (n <= 0)
61731203Sbrian      DropClient();
6186059Samurai    return;
6196059Samurai  }
6206059Samurai
6216059Samurai  /*
62228679Sbrian   * We are in terminal mode, decode special sequences
6236059Samurai   */
62426516Sbrian  n = read(fileno(VarTerm), &ch, 1);
62528974Sbrian  LogPrintf(LogDEBUG, "Got %d bytes (reading from the terminal)\n", n);
6266059Samurai
6276059Samurai  if (n > 0) {
6286059Samurai    switch (ttystate) {
6296059Samurai    case 0:
6306059Samurai      if (ch == '~')
6316059Samurai	ttystate++;
6326059Samurai      else
6336059Samurai	write(modem, &ch, n);
6346059Samurai      break;
6356059Samurai    case 1:
6366059Samurai      switch (ch) {
6376059Samurai      case '?':
6386059Samurai	ShowHelp();
6396059Samurai	break;
6406059Samurai      case 'p':
64128679Sbrian
6426059Samurai	/*
6436059Samurai	 * XXX: Should check carrier.
6446059Samurai	 */
6456059Samurai	if (LcpFsm.state <= ST_CLOSED) {
6466059Samurai	  VarOpenMode = OPEN_ACTIVE;
6476059Samurai	  PacketMode();
6486059Samurai	}
6496059Samurai	break;
6506059Samurai      case '.':
6516059Samurai	TermMode = 1;
65226516Sbrian	aft_cmd = 1;
65310528Samurai	TtyCommandMode(1);
6546059Samurai	break;
65526516Sbrian      case 't':
65626516Sbrian	if (LogIsKept(LogDEBUG)) {
65726516Sbrian	  ShowTimers();
65826516Sbrian	  break;
65926516Sbrian	}
66026516Sbrian      case 'm':
66126516Sbrian	if (LogIsKept(LogDEBUG)) {
66231343Sbrian	  ShowMemMap(NULL);
66326516Sbrian	  break;
66426516Sbrian	}
6656059Samurai      default:
6666059Samurai	if (write(modem, &ch, n) < 0)
66726516Sbrian	  LogPrintf(LogERROR, "error writing to modem.\n");
6686059Samurai	break;
6696059Samurai      }
6706059Samurai      ttystate = 0;
6716059Samurai      break;
6726059Samurai    }
6736059Samurai  }
6746059Samurai}
6756059Samurai
6766059Samurai
6776059Samurai/*
6786059Samurai *  Here, we'll try to detect HDLC frame
6796059Samurai */
6806059Samurai
68131343Sbrianstatic const char *FrameHeaders[] = {
6826735Samurai  "\176\377\003\300\041",
6836735Samurai  "\176\377\175\043\300\041",
6846735Samurai  "\176\177\175\043\100\041",
6856735Samurai  "\176\175\337\175\043\300\041",
6866735Samurai  "\176\175\137\175\043\100\041",
6876059Samurai  NULL,
6886059Samurai};
6896059Samurai
69031343Sbrianstatic const u_char *
69128679SbrianHdlcDetect(u_char * cp, int n)
6926059Samurai{
69331343Sbrian  const char *ptr, *fp, **hp;
6946059Samurai
69528679Sbrian  cp[n] = '\0';			/* be sure to null terminated */
6966059Samurai  ptr = NULL;
6976059Samurai  for (hp = FrameHeaders; *hp; hp++) {
6986735Samurai    fp = *hp;
6996735Samurai    if (DEV_IS_SYNC)
7006735Samurai      fp++;
70128679Sbrian    ptr = strstr((char *) cp, fp);
70213389Sphk    if (ptr)
7036059Samurai      break;
7046059Samurai  }
70531343Sbrian  return ((const u_char *) ptr);
7066059Samurai}
7076059Samurai
7086059Samuraistatic struct pppTimer RedialTimer;
7096059Samurai
7106059Samuraistatic void
71131343SbrianRedialTimeout(void *v)
7126059Samurai{
7136059Samurai  StopTimer(&RedialTimer);
71426516Sbrian  LogPrintf(LogPHASE, "Redialing timer expired.\n");
7156059Samurai}
7166059Samurai
7176059Samuraistatic void
71828679SbrianStartRedialTimer(int Timeout)
7196059Samurai{
7206059Samurai  StopTimer(&RedialTimer);
72111336Samurai
72224939Sbrian  if (Timeout) {
72311336Samurai    RedialTimer.state = TIMER_STOPPED;
72411336Samurai
72524939Sbrian    if (Timeout > 0)
72628679Sbrian      RedialTimer.load = Timeout * SECTICKS;
72711336Samurai    else
72828679Sbrian      RedialTimer.load = (random() % REDIAL_PERIOD) * SECTICKS;
72911336Samurai
73026516Sbrian    LogPrintf(LogPHASE, "Enter pause (%d) for redialing.\n",
73124939Sbrian	      RedialTimer.load / SECTICKS);
73224939Sbrian
73311336Samurai    RedialTimer.func = RedialTimeout;
73411336Samurai    StartTimer(&RedialTimer);
73511336Samurai  }
7366059Samurai}
7376059Samurai
7386059Samurai
7396059Samuraistatic void
74031343SbrianDoLoop(void)
7416059Samurai{
7426059Samurai  fd_set rfds, wfds, efds;
74323598Sache  int pri, i, n, wfd, nfds;
7446059Samurai  struct sockaddr_in hisaddr;
7456059Samurai  struct timeval timeout, *tp;
7466059Samurai  int ssize = sizeof(hisaddr);
74731343Sbrian  const u_char *cp;
74811336Samurai  int tries;
7499448Samurai  int qlen;
75026858Sbrian  int res;
75131195Sbrian  struct tun_data tun;
75231195Sbrian#define rbuff tun.data
7536059Samurai
75425908Sbrian  if (mode & MODE_DIRECT) {
75526551Sbrian    LogPrintf(LogDEBUG, "Opening modem\n");
75631034Sbrian    if (OpenModem() < 0)
75729521Sbrian      return;
75826516Sbrian    LogPrintf(LogPHASE, "Packet mode enabled\n");
7596059Samurai    PacketMode();
7606059Samurai  } else if (mode & MODE_DEDICATED) {
76123598Sache    if (modem < 0)
76231034Sbrian      while (OpenModem() < 0)
76330697Sbrian	nointr_sleep(VarReconnectTimer);
7646059Samurai  }
76526516Sbrian  fflush(VarTerm);
7666059Samurai
7677001Samurai  timeout.tv_sec = 0;
7686059Samurai  timeout.tv_usec = 0;
76926098Sbrian  reconnectState = RECON_UNKNOWN;
7706059Samurai
77123863Sbrian  if (mode & MODE_BACKGROUND)
77230715Sbrian    dial_up = 1;		/* Bring the line up */
77323863Sbrian  else
77430715Sbrian    dial_up = 0;		/* XXXX */
77511336Samurai  tries = 0;
7766059Samurai  for (;;) {
77723598Sache    nfds = 0;
77828679Sbrian    FD_ZERO(&rfds);
77928679Sbrian    FD_ZERO(&wfds);
78028679Sbrian    FD_ZERO(&efds);
7817001Samurai
78228679Sbrian    /*
78328679Sbrian     * If the link is down and we're in DDIAL mode, bring it back up.
78420120Snate     */
78520120Snate    if (mode & MODE_DDIAL && LcpFsm.state <= ST_CLOSED)
78630715Sbrian      dial_up = 1;
78720120Snate
78825067Sbrian    /*
78928679Sbrian     * If we lost carrier and want to re-establish the connection due to the
79028679Sbrian     * "set reconnect" value, we'd better bring the line back up.
79125067Sbrian     */
79225908Sbrian    if (LcpFsm.state <= ST_CLOSED) {
79330715Sbrian      if (!dial_up && reconnectState == RECON_TRUE) {
79428679Sbrian	if (++reconnectCount <= VarReconnectTries) {
79528679Sbrian	  LogPrintf(LogPHASE, "Connection lost, re-establish (%d/%d)\n",
79628679Sbrian		    reconnectCount, VarReconnectTries);
79725908Sbrian	  StartRedialTimer(VarReconnectTimer);
79830715Sbrian	  dial_up = 1;
79928679Sbrian	} else {
80028679Sbrian	  if (VarReconnectTries)
80128679Sbrian	    LogPrintf(LogPHASE, "Connection lost, maximum (%d) times\n",
80228679Sbrian		      VarReconnectTries);
80328679Sbrian	  reconnectCount = 0;
80428679Sbrian	  if (mode & MODE_BACKGROUND)
80528679Sbrian	    Cleanup(EX_DEAD);
80628679Sbrian	}
80728679Sbrian	reconnectState = RECON_ENVOKED;
80831121Sbrian      } else if (mode & MODE_DEDICATED)
80931121Sbrian        if (VarOpenMode == OPEN_ACTIVE)
81031121Sbrian          PacketMode();
81125908Sbrian    }
81225067Sbrian
81328679Sbrian    /*
81428679Sbrian     * If Ip packet for output is enqueued and require dial up, Just do it!
81528679Sbrian     */
81628679Sbrian    if (dial_up && RedialTimer.state != TIMER_RUNNING) {
81726516Sbrian      LogPrintf(LogDEBUG, "going to dial: modem = %d\n", modem);
81831034Sbrian      if (OpenModem() < 0) {
81928679Sbrian	tries++;
82028679Sbrian	if (!(mode & MODE_DDIAL) && VarDialTries)
82128679Sbrian	  LogPrintf(LogCHAT, "Failed to open modem (attempt %u of %d)\n",
82228679Sbrian		    tries, VarDialTries);
82328679Sbrian	else
82428679Sbrian	  LogPrintf(LogCHAT, "Failed to open modem (attempt %u)\n", tries);
82526551Sbrian
82626696Sbrian	if (!(mode & MODE_DDIAL) && VarDialTries && tries >= VarDialTries) {
82726551Sbrian	  if (mode & MODE_BACKGROUND)
82828679Sbrian	    Cleanup(EX_DIAL);	/* Can't get the modem */
82930715Sbrian	  dial_up = 0;
83028679Sbrian	  reconnectState = RECON_UNKNOWN;
83128679Sbrian	  reconnectCount = 0;
83226551Sbrian	  tries = 0;
83328679Sbrian	} else
83426551Sbrian	  StartRedialTimer(VarRedialTimeout);
83511336Samurai      } else {
83628679Sbrian	tries++;		/* Tries are per number, not per list of
83728679Sbrian				 * numbers. */
83828679Sbrian	if (!(mode & MODE_DDIAL) && VarDialTries)
83926696Sbrian	  LogPrintf(LogCHAT, "Dial attempt %u of %d\n", tries, VarDialTries);
84028679Sbrian	else
84128679Sbrian	  LogPrintf(LogCHAT, "Dial attempt %u\n", tries);
84226696Sbrian
84326858Sbrian	if ((res = DialModem()) == EX_DONE) {
84430697Sbrian	  nointr_sleep(1);		/* little pause to allow peer starts */
84531343Sbrian	  ModemTimeout(NULL);
84611336Samurai	  PacketMode();
84730715Sbrian	  dial_up = 0;
84828679Sbrian	  reconnectState = RECON_UNKNOWN;
84911336Samurai	  tries = 0;
85011336Samurai	} else {
85124844Sbrian	  if (mode & MODE_BACKGROUND) {
85226858Sbrian	    if (VarNextPhone == NULL || res == EX_SIG)
85328679Sbrian	      Cleanup(EX_DIAL);	/* Tried all numbers - no luck */
85424844Sbrian	    else
85524939Sbrian	      /* Try all numbers in background mode */
85624939Sbrian	      StartRedialTimer(VarRedialNextTimeout);
85726858Sbrian	  } else if (!(mode & MODE_DDIAL) &&
85828679Sbrian		     ((VarDialTries && tries >= VarDialTries) ||
85928679Sbrian		      res == EX_SIG)) {
86024843Sbrian	    /* I give up !  Can't get through :( */
86124939Sbrian	    StartRedialTimer(VarRedialTimeout);
86230715Sbrian	    dial_up = 0;
86328679Sbrian	    reconnectState = RECON_UNKNOWN;
86428679Sbrian	    reconnectCount = 0;
86524843Sbrian	    tries = 0;
86624843Sbrian	  } else if (VarNextPhone == NULL)
86724843Sbrian	    /* Dial failed. Keep quite during redial wait period. */
86824939Sbrian	    StartRedialTimer(VarRedialTimeout);
86924843Sbrian	  else
87024939Sbrian	    StartRedialTimer(VarRedialNextTimeout);
87111336Samurai	}
87211336Samurai      }
8737001Samurai    }
8749448Samurai    qlen = ModemQlen();
87513733Sdfr
87613733Sdfr    if (qlen == 0) {
87713733Sdfr      IpStartOutput();
87813733Sdfr      qlen = ModemQlen();
87913733Sdfr    }
88023598Sache    if (modem >= 0) {
88123598Sache      if (modem + 1 > nfds)
88223598Sache	nfds = modem + 1;
8837001Samurai      FD_SET(modem, &rfds);
8847001Samurai      FD_SET(modem, &efds);
8859448Samurai      if (qlen > 0) {
8867001Samurai	FD_SET(modem, &wfds);
8877001Samurai      }
8887001Samurai    }
88923598Sache    if (server >= 0) {
89023598Sache      if (server + 1 > nfds)
89123598Sache	nfds = server + 1;
89223598Sache      FD_SET(server, &rfds);
89323598Sache    }
8946059Samurai
89528679Sbrian    /*
89628679Sbrian     * *** IMPORTANT ***
89728679Sbrian     *
89828679Sbrian     * CPU is serviced every TICKUNIT micro seconds. This value must be chosen
89928679Sbrian     * with great care. If this values is too big, it results loss of
90028679Sbrian     * characters from modem and poor responce. If this values is too small,
90128679Sbrian     * ppp process eats many CPU time.
9026059Samurai     */
9036735Samurai#ifndef SIGALRM
90430697Sbrian    nointr_usleep(TICKUNIT);
9056059Samurai    TimerService();
90623840Sbrian#else
90723840Sbrian    handle_signals();
9086735Samurai#endif
90910877Sbde
91010877Sbde    /* If there are aren't many packets queued, look for some more. */
91123598Sache    if (qlen < 20 && tun_in >= 0) {
91223598Sache      if (tun_in + 1 > nfds)
91323598Sache	nfds = tun_in + 1;
91410877Sbde      FD_SET(tun_in, &rfds);
91523598Sache    }
91623598Sache    if (netfd >= 0) {
91723598Sache      if (netfd + 1 > nfds)
91823598Sache	nfds = netfd + 1;
9196059Samurai      FD_SET(netfd, &rfds);
9206059Samurai      FD_SET(netfd, &efds);
9216059Samurai    }
92228679Sbrian#ifndef SIGALRM
9237001Samurai
9246059Samurai    /*
92528679Sbrian     * Normally, select() will not block because modem is writable. In AUTO
92628679Sbrian     * mode, select will block until we find packet from tun
9276059Samurai     */
92828679Sbrian    tp = (RedialTimer.state == TIMER_RUNNING) ? &timeout : NULL;
92923598Sache    i = select(nfds, &rfds, &wfds, &efds, tp);
9306735Samurai#else
93128679Sbrian
9328857Srgrimes    /*
93328679Sbrian     * When SIGALRM timer is running, a select function will be return -1 and
93428679Sbrian     * EINTR after a Time Service signal hundler is done.  If the redial
93528679Sbrian     * timer is not running and we are trying to dial, poll with a 0 value
93628679Sbrian     * timer.
9377001Samurai     */
93811336Samurai    tp = (dial_up && RedialTimer.state != TIMER_RUNNING) ? &timeout : NULL;
93923598Sache    i = select(nfds, &rfds, &wfds, &efds, tp);
9406735Samurai#endif
94122074Sbrian
94228679Sbrian    if (i == 0) {
94328679Sbrian      continue;
9446059Samurai    }
94528679Sbrian    if (i < 0) {
94628679Sbrian      if (errno == EINTR) {
94728679Sbrian	handle_signals();
94828679Sbrian	continue;
94928679Sbrian      }
95028974Sbrian      LogPrintf(LogERROR, "DoLoop: select(): %s\n", strerror(errno));
95128679Sbrian      break;
9528857Srgrimes    }
95323598Sache    if ((netfd >= 0 && FD_ISSET(netfd, &efds)) || (modem >= 0 && FD_ISSET(modem, &efds))) {
95426516Sbrian      LogPrintf(LogALERT, "Exception detected.\n");
9556059Samurai      break;
9566059Samurai    }
95723598Sache    if (server >= 0 && FD_ISSET(server, &rfds)) {
95826516Sbrian      LogPrintf(LogPHASE, "connected to client.\n");
95928679Sbrian      wfd = accept(server, (struct sockaddr *) & hisaddr, &ssize);
96024753Sache      if (wfd < 0) {
96128974Sbrian	LogPrintf(LogERROR, "DoLoop: accept(): %s\n", strerror(errno));
96224753Sache	continue;
96324753Sache      }
96423598Sache      if (netfd >= 0) {
9656059Samurai	write(wfd, "already in use.\n", 16);
9666059Samurai	close(wfd);
9676059Samurai	continue;
9686059Samurai      } else
9696059Samurai	netfd = wfd;
97026516Sbrian      VarTerm = fdopen(netfd, "a+");
97131081Sbrian      LocalAuthInit();
9726059Samurai      Greetings();
97330913Sbrian      IsInteractive(1);
97425630Sbrian      Prompt();
9756059Samurai    }
97631514Sbrian    if (netfd >= 0 && FD_ISSET(netfd, &rfds))
9776059Samurai      /* something to read from tty */
9786059Samurai      ReadTty();
97931514Sbrian    if (modem >= 0 && FD_ISSET(modem, &wfds)) {
98031514Sbrian      /* ready to write into modem */
98131514Sbrian      ModemStartOutput(modem);
98231514Sbrian      if (modem < 0)
98331514Sbrian        dial_up = 1;
9846059Samurai    }
98531514Sbrian    if (modem >= 0 && FD_ISSET(modem, &rfds)) {
98631514Sbrian      /* something to read from modem */
98731514Sbrian      if (LcpFsm.state <= ST_CLOSED)
98831514Sbrian	nointr_usleep(10000);
98931514Sbrian      n = read(modem, rbuff, sizeof(rbuff));
99031514Sbrian      if ((mode & MODE_DIRECT) && n <= 0) {
99131514Sbrian	DownConnection();
99231514Sbrian      } else
99331514Sbrian	LogDumpBuff(LogASYNC, "ReadFromModem", rbuff, n);
9946059Samurai
99531514Sbrian      if (LcpFsm.state <= ST_CLOSED) {
99631514Sbrian	/*
99731514Sbrian	 * In dedicated mode, we just discard input until LCP is started.
99831514Sbrian	 */
99931514Sbrian	if (!(mode & MODE_DEDICATED)) {
100031514Sbrian	  cp = HdlcDetect(rbuff, n);
100131514Sbrian	  if (cp) {
100231514Sbrian	    /*
100331514Sbrian	     * LCP packet is detected. Turn ourselves into packet mode.
100431514Sbrian	     */
100531514Sbrian	    if (cp != rbuff) {
100631514Sbrian	      write(modem, rbuff, cp - rbuff);
100731514Sbrian	      write(modem, "\r\n", 2);
100831514Sbrian	    }
100931514Sbrian	    PacketMode();
101031514Sbrian	  } else
101131514Sbrian	    write(fileno(VarTerm), rbuff, n);
10126059Samurai	}
101331514Sbrian      } else {
101431514Sbrian	if (n > 0)
101531514Sbrian	  AsyncInput(rbuff, n);
10166059Samurai      }
10176059Samurai    }
101828679Sbrian    if (tun_in >= 0 && FD_ISSET(tun_in, &rfds)) {	/* something to read
101928679Sbrian							 * from tun */
102031195Sbrian      n = read(tun_in, &tun, sizeof(tun));
10216059Samurai      if (n < 0) {
102228974Sbrian	LogPrintf(LogERROR, "read from tun: %s\n", strerror(errno));
10236059Samurai	continue;
10246059Samurai      }
102531195Sbrian      n -= sizeof(tun)-sizeof(tun.data);
102631195Sbrian      if (n <= 0) {
102731195Sbrian	LogPrintf(LogERROR, "read from tun: Only %d bytes read\n", n);
102831195Sbrian	continue;
102931195Sbrian      }
103031195Sbrian      if (!tun_check_header(tun, AF_INET))
103131195Sbrian          continue;
103228679Sbrian      if (((struct ip *) rbuff)->ip_dst.s_addr == IpcpInfo.want_ipaddr.s_addr) {
103328536Sbrian	/* we've been asked to send something addressed *to* us :( */
103428536Sbrian	if (VarLoopback) {
103528536Sbrian	  pri = PacketCheck(rbuff, n, FL_IN);
103628536Sbrian	  if (pri >= 0) {
103728536Sbrian	    struct mbuf *bp;
103828679Sbrian
103931343Sbrian#ifndef NOALIAS
104028536Sbrian	    if (mode & MODE_ALIAS) {
104128536Sbrian	      VarPacketAliasIn(rbuff, sizeof rbuff);
104228679Sbrian	      n = ntohs(((struct ip *) rbuff)->ip_len);
104328536Sbrian	    }
104431343Sbrian#endif
104528536Sbrian	    bp = mballoc(n, MB_IPIN);
104630715Sbrian	    memcpy(MBUF_CTOP(bp), rbuff, n);
104728536Sbrian	    IpInput(bp);
104828536Sbrian	    LogPrintf(LogDEBUG, "Looped back packet addressed to myself\n");
104928536Sbrian	  }
105028536Sbrian	  continue;
105128679Sbrian	} else
105228536Sbrian	  LogPrintf(LogDEBUG, "Oops - forwarding packet addressed to myself\n");
105328536Sbrian      }
105428536Sbrian
10556059Samurai      /*
105628679Sbrian       * Process on-demand dialup. Output packets are queued within tunnel
105728679Sbrian       * device until IPCP is opened.
10586059Samurai       */
10596059Samurai      if (LcpFsm.state <= ST_CLOSED && (mode & MODE_AUTO)) {
10607001Samurai	pri = PacketCheck(rbuff, n, FL_DIAL);
10616059Samurai	if (pri >= 0) {
106231343Sbrian#ifndef NOALIAS
106320365Sjkh	  if (mode & MODE_ALIAS) {
106426142Sbrian	    VarPacketAliasOut(rbuff, sizeof rbuff);
106528679Sbrian	    n = ntohs(((struct ip *) rbuff)->ip_len);
106620365Sjkh	  }
106731343Sbrian#endif
10686059Samurai	  IpEnqueue(pri, rbuff, n);
106930715Sbrian	  dial_up = 1;	/* XXX */
10706059Samurai	}
10716059Samurai	continue;
10726059Samurai      }
10737001Samurai      pri = PacketCheck(rbuff, n, FL_OUT);
107420365Sjkh      if (pri >= 0) {
107531343Sbrian#ifndef NOALIAS
107628679Sbrian	if (mode & MODE_ALIAS) {
107728679Sbrian	  VarPacketAliasOut(rbuff, sizeof rbuff);
107828679Sbrian	  n = ntohs(((struct ip *) rbuff)->ip_len);
107928679Sbrian	}
108031343Sbrian#endif
10816059Samurai	IpEnqueue(pri, rbuff, n);
108220365Sjkh      }
10836059Samurai    }
10846059Samurai  }
108526516Sbrian  LogPrintf(LogDEBUG, "Job (DoLoop) done.\n");
10866059Samurai}
1087